From def4ca699a700d5f3547de96d20db49de37f2b78 Mon Sep 17 00:00:00 2001 From: Knut Sveidqvist Date: Thu, 12 Sep 2019 21:03:49 +0200 Subject: [PATCH 01/13] #931 added conf and libraries --- .eslintrc.json | 18 +++ .prettierrc | 4 + package.json | 4 + yarn.lock | 333 ++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 345 insertions(+), 14 deletions(-) create mode 100644 .eslintrc.json create mode 100644 .prettierrc diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 000000000..a1aed17d7 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "env": { + "browser": true, + "es6": true + }, + "parserOptions": { + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + }, + "sourceType": "module" + }, + "extends": ["prettier"], + "plugins": ["prettier"], + "rules": { + "prettier/prettier": ["error"] + } +} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..5ac85e271 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "printWidth": 100, + "singleQuote": true +} diff --git a/package.json b/package.json index 059f3cc99..1c63b6565 100644 --- a/package.json +++ b/package.json @@ -51,11 +51,15 @@ "dagre-d3-renderer": "^0.5.8", "dagre-layout": "^0.8.8", "documentation": "^12.0.1", + "eslint": "^6.3.0", + "eslint-config-prettier": "^6.3.0", + "eslint-plugin-prettier": "^3.1.0", "graphlibrary": "^2.2.0", "he": "^1.2.0", "lodash": "^4.17.11", "minify": "^4.1.1", "moment-mini": "^2.22.1", + "prettier": "^1.18.2", "scope-css": "^1.2.1" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 28ea2faba..7864a312a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -916,6 +916,13 @@ pirates "^4.0.0" source-map-support "^0.5.9" +"@babel/runtime@^7.4.5": + version "7.6.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.0.tgz#4fc1d642a9fd0299754e8b5de62c631cf5568205" + integrity sha512-89eSBLJsxNxOERC0Op4vd+0Bqm6wRMqMbFtV3i0/fbaWw/mJ8Q3eBvgX0G4SyrOOLCtbu98HspF8o09MRT+KzQ== + dependencies: + regenerator-runtime "^0.13.2" + "@babel/template@^7.1.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0": version "7.6.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6" @@ -1381,7 +1388,7 @@ acorn-globals@^4.1.0: acorn "^6.0.1" acorn-walk "^6.0.1" -acorn-jsx@^5.0.0: +acorn-jsx@^5.0.0, acorn-jsx@^5.0.2: version "5.0.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw== @@ -1401,6 +1408,11 @@ acorn@^6.0.1, acorn@^6.0.2, acorn@^6.2.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== +acorn@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a" + integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ== + agent-base@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" @@ -1418,7 +1430,7 @@ ajv-keywords@^3.0.0, ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== -ajv@^6.0.1, ajv@^6.1.0, ajv@^6.10.2, ajv@^6.5.0, ajv@^6.5.5: +ajv@^6.0.1, ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.0, ajv@^6.5.5: version "6.10.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== @@ -1443,7 +1455,7 @@ ansi-escapes@^1.0.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= -ansi-escapes@^3.0.0, ansi-escapes@^3.1.0: +ansi-escapes@^3.0.0, ansi-escapes@^3.1.0, ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== @@ -1537,6 +1549,14 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +aria-query@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" + integrity sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w= + dependencies: + ast-types-flow "0.0.7" + commander "^2.11.0" + arr-diff@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" @@ -1653,6 +1673,11 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +ast-types-flow@0.0.7, ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" @@ -1733,6 +1758,13 @@ axios@^0.19.0: follow-redirects "1.5.10" is-buffer "^2.0.2" +axobject-query@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" + integrity sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww== + dependencies: + ast-types-flow "0.0.7" + babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -2311,6 +2343,11 @@ callsites@^2.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camel-case@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" @@ -2431,6 +2468,11 @@ chardet@^0.4.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + check-more-types@2.24.0: version "2.24.0" resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" @@ -2790,6 +2832,11 @@ concat-stream@~1.5.0: readable-stream "~2.0.0" typedarray "~0.0.5" +confusing-browser-globals@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.8.tgz#93ffec1f82a6e2bf2bc36769cc3a92fa20e502f3" + integrity sha512-lI7asCibVJ6Qd3FGU7mu4sfG4try4LX3+GVS+Gv8UlrEf2AeW57piecapnog2UHZSbcX/P/1UDWVaTsblowlZg== + connect-history-api-fallback@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" @@ -3363,6 +3410,11 @@ dagre-layout@^0.8.8: graphlibrary "^2.2.0" lodash "^4.17.5" +damerau-levenshtein@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz#780cf7144eb2e8dbd1c3bb83ae31100ccc31a414" + integrity sha512-CBCRqFnpu715iPmw1KrdOrzRqbdFwQTwAWyyyYS42+iAgHCuXZ+/TdMgQkUENPomxEz9z1BEzuQU2Xw0kUuAgA== + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -3413,7 +3465,7 @@ debug@3.2.6, debug@^3.0.0, debug@^3.1.0, debug@^3.2.5, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@4.1.1, debug@^4.1.0, debug@^4.1.1: +debug@4.1.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -3676,6 +3728,13 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + documentation@^12.0.1: version "12.1.2" resolved "https://registry.yarnpkg.com/documentation/-/documentation-12.1.2.tgz#4ed9ab511363504da7a0c120d192a366bd6b994a" @@ -3827,7 +3886,7 @@ elliptic@^6.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-6.1.1.tgz#c6cd0ec1b0642e2a3c67a1137efc5e796da4f88e" integrity sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4= -emoji-regex@^7.0.1: +emoji-regex@^7.0.1, emoji-regex@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== @@ -3885,7 +3944,7 @@ error@^7.0.0: string-template "~0.2.1" xtend "~4.0.0" -es-abstract@^1.5.1, es-abstract@^1.7.0: +es-abstract@^1.12.0, es-abstract@^1.5.1, es-abstract@^1.7.0: version "1.14.2" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497" integrity sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg== @@ -3965,6 +4024,31 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-config-airbnb-base@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.0.0.tgz#8a7bcb9643d13c55df4dd7444f138bf4efa61e17" + integrity sha512-2IDHobw97upExLmsebhtfoD3NAKhV4H0CJWP3Uprd/uk+cHuWYOczPVxQ8PxLFUAw7o3Th1RAU8u1DoUpr+cMA== + dependencies: + confusing-browser-globals "^1.0.7" + object.assign "^4.1.0" + object.entries "^1.1.0" + +eslint-config-airbnb@^18.0.1: + version "18.0.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.0.1.tgz#a3a74cc29b46413b6096965025381df8fb908559" + integrity sha512-hLb/ccvW4grVhvd6CT83bECacc+s4Z3/AEyWQdIT2KeTsG9dR7nx1gs7Iw4tDmGKozCNHFn4yZmRm3Tgy+XxyQ== + dependencies: + eslint-config-airbnb-base "^14.0.0" + object.assign "^4.1.0" + object.entries "^1.1.0" + +eslint-config-prettier@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.3.0.tgz#e73b48e59dc49d950843f3eb96d519e2248286a3" + integrity sha512-EWaGjlDAZRzVFveh2Jsglcere2KK5CJBhkNSa1xs3KfMUGdRiT7lG089eqPdvlzWHpAqaekubOsOMu8W8Yk71A== + dependencies: + get-stdin "^6.0.0" + eslint-config-standard-jsx@6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-6.0.2.tgz#90c9aa16ac2c4f8970c13fc7efc608bacd02da70" @@ -4015,6 +4099,21 @@ eslint-plugin-import@~2.14.0: read-pkg-up "^2.0.0" resolve "^1.6.0" +eslint-plugin-jsx-a11y@^6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.3.tgz#b872a09d5de51af70a97db1eea7dc933043708aa" + integrity sha512-CawzfGt9w83tyuVekn0GDPU9ytYtxyxyFZ3aSWROmnRRFQFT2BiPJd7jvRdzNDi6oLWaS2asMeYSNMjWTV4eNg== + dependencies: + "@babel/runtime" "^7.4.5" + aria-query "^3.0.0" + array-includes "^3.0.3" + ast-types-flow "^0.0.7" + axobject-query "^2.0.2" + damerau-levenshtein "^1.0.4" + emoji-regex "^7.0.2" + has "^1.0.3" + jsx-ast-utils "^2.2.1" + eslint-plugin-node@~7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-7.0.1.tgz#a6e054e50199b2edd85518b89b4e7b323c9f36db" @@ -4027,6 +4126,13 @@ eslint-plugin-node@~7.0.1: resolve "^1.8.1" semver "^5.5.0" +eslint-plugin-prettier@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz#8695188f95daa93b0dc54b249347ca3b79c4686d" + integrity sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-plugin-promise@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz#2d074b653f35a23d1ba89d8e976a985117d1c6a2" @@ -4056,6 +4162,14 @@ eslint-scope@^4.0.0, eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^1.3.1, eslint-utils@^1.4.2: version "1.4.2" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" @@ -4063,11 +4177,54 @@ eslint-utils@^1.3.1, eslint-utils@^1.4.2: dependencies: eslint-visitor-keys "^1.0.0" -eslint-visitor-keys@^1.0.0: +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== +eslint@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.3.0.tgz#1f1a902f67bfd4c354e7288b81e40654d927eb6a" + integrity sha512-ZvZTKaqDue+N8Y9g0kp6UPZtS4FSY3qARxBs7p4f0H0iof381XHduqVerFWtK8DPtKmemqbqCFENWSQgPR/Gow== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.2" + eslint-visitor-keys "^1.1.0" + espree "^6.1.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.4.1" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + eslint@~5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.4.0.tgz#d068ec03006bb9e06b429dc85f7e46c1b69fac62" @@ -4121,6 +4278,15 @@ espree@^4.0.0: acorn-jsx "^5.0.0" eslint-visitor-keys "^1.0.0" +espree@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" + integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== + dependencies: + acorn "^7.0.0" + acorn-jsx "^5.0.2" + eslint-visitor-keys "^1.1.0" + esprima@1.1.x, esprima@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.1.1.tgz#5b6f1547f4d102e670e140c509be6771d6aeb549" @@ -4412,6 +4578,15 @@ external-editor@^2.1.0: iconv-lite "^0.4.17" tmp "^0.0.33" +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -4468,6 +4643,11 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + fast-glob@^3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.0.4.tgz#d484a41005cb6faeb399b951fd1bd70ddaebb602" @@ -4560,6 +4740,13 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -4694,6 +4881,20 @@ flat-cache@^1.2.1: rimraf "~2.6.2" write "^0.2.1" +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" @@ -5515,7 +5716,7 @@ hyperlinker@^1.0.0: resolved "https://registry.yarnpkg.com/hyperlinker/-/hyperlinker-1.0.0.tgz#23dc9e38a206b208ee49bc2d6c8ef47027df0c0e" integrity sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ== -iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.4: +iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -5563,7 +5764,7 @@ ignore@^3.0.9: resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== -ignore@^4.0.2: +ignore@^4.0.2, ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== @@ -5581,6 +5782,14 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" +import-fresh@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" + integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-local@2.0.0, import-local@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" @@ -5676,6 +5885,25 @@ inquirer@^5.2.0: strip-ansi "^4.0.0" through "^2.3.6" +inquirer@^6.4.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + internal-ip@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" @@ -6778,7 +7006,7 @@ jssha@^2.1.0: resolved "https://registry.yarnpkg.com/jssha/-/jssha-2.3.1.tgz#147b2125369035ca4b2f7d210dc539f009b3de9a" integrity sha1-FHshJTaQNcpLL30hDcU58Amz3po= -jsx-ast-utils@^2.0.1: +jsx-ast-utils@^2.0.1, jsx-ast-utils@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.2.1.tgz#4d4973ebf8b9d2837ee91a8208cc66f3a2776cfb" integrity sha512-v3FxCcAf20DayI+uxnCuw795+oOIkVu6EnJ1+kSzhqqTZHNkTZ7B66ZgLp4oLJ/gbA64cI0B7WRoHZMSRdyVRQ== @@ -7060,7 +7288,7 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "^3.0.0" -lodash@4.17.15, lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.10: +lodash@4.17.15, lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.10: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -7952,6 +8180,16 @@ object.assign@^4.0.4, object.assign@^4.1.0: has-symbols "^1.0.0" object-keys "^1.0.11" +object.entries@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" + integrity sha512-l+H6EQ8qzGRxbkHOd5I/aHRhHDKoQXQ8g0BYt4uSweQU1/J6dZUOyWh9a2Vky35YCKjzmgxOzta2hH6kf9HuXA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.12.0" + function-bind "^1.1.1" + has "^1.0.3" + object.getownpropertydescriptors@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" @@ -8201,6 +8439,13 @@ param-case@^2.1.1: dependencies: no-case "^2.2.0" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-asn1@^5.0.0: version "5.1.4" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" @@ -8618,6 +8863,18 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" + integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== + pretty-format@^23.6.0: version "23.6.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760" @@ -9054,7 +9311,7 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.1: +regenerator-runtime@^0.13.1, regenerator-runtime@^0.13.2: version "0.13.3" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== @@ -9375,6 +9632,11 @@ resolve-from@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" integrity sha1-six699nWiBvItuZTM17rywoYh0g= +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-options@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" @@ -9442,7 +9704,7 @@ rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: dependencies: glob "^7.1.3" -rimraf@~2.6.2: +rimraf@2.6.3, rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== @@ -9503,6 +9765,13 @@ rxjs@^5.0.0-beta.11, rxjs@^5.5.2: dependencies: symbol-observable "1.0.1" +rxjs@^6.4.0: + version "6.5.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a" + integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA== + dependencies: + tslib "^1.9.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -9620,7 +9889,7 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.3.0: +semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -9791,6 +10060,15 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + slugify@^1.3.1: version "1.3.5" resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.3.5.tgz#90210678818b6d533cb060083aed0e8238133508" @@ -10315,6 +10593,11 @@ strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= +strip-json-comments@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" + integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== + subarg@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" @@ -10378,6 +10661,16 @@ table@^4.0.3: slice-ansi "1.0.0" string-width "^2.1.1" +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + tapable@^1.0.0, tapable@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" @@ -10974,6 +11267,11 @@ v8-compile-cache@2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== +v8-compile-cache@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -11456,6 +11754,13 @@ write-file-atomic@^2.1.0: imurmurhash "^0.1.4" signal-exit "^3.0.2" +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" From f2a6ba80b5cd6fa1a2fc94ac66d8eea8e64c3b19 Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:54:59 -0700 Subject: [PATCH 02/13] #931 Aligning code standard --- src/diagrams/sequence/svgDraw.js | 403 ++++++++++++++------------ src/diagrams/sequence/svgDraw.spec.js | 94 +++--- 2 files changed, 272 insertions(+), 225 deletions(-) diff --git a/src/diagrams/sequence/svgDraw.js b/src/diagrams/sequence/svgDraw.js index c33e470cc..4658f174f 100644 --- a/src/diagrams/sequence/svgDraw.js +++ b/src/diagrams/sequence/svgDraw.js @@ -1,71 +1,87 @@ -export const drawRect = function (elem, rectData) { - const rectElem = elem.append('rect') - rectElem.attr('x', rectData.x) - rectElem.attr('y', rectData.y) - rectElem.attr('fill', rectData.fill) - rectElem.attr('stroke', rectData.stroke) - rectElem.attr('width', rectData.width) - rectElem.attr('height', rectData.height) - rectElem.attr('rx', rectData.rx) - rectElem.attr('ry', rectData.ry) +export const drawRect = function(elem, rectData) { + const rectElem = elem.append('rect'); + rectElem.attr('x', rectData.x); + rectElem.attr('y', rectData.y); + rectElem.attr('fill', rectData.fill); + rectElem.attr('stroke', rectData.stroke); + rectElem.attr('width', rectData.width); + rectElem.attr('height', rectData.height); + rectElem.attr('rx', rectData.rx); + rectElem.attr('ry', rectData.ry); if (typeof rectData.class !== 'undefined') { - rectElem.attr('class', rectData.class) + rectElem.attr('class', rectData.class); } - return rectElem -} + return rectElem; +}; -export const drawText = function (elem, textData, width) { +export const drawText = function(elem, textData, width) { // Remove and ignore br:s - const nText = textData.text.replace(//ig, ' ') + const nText = textData.text.replace(//gi, ' '); - const textElem = elem.append('text') - textElem.attr('x', textData.x) - textElem.attr('y', textData.y) - textElem.style('text-anchor', textData.anchor) - textElem.attr('fill', textData.fill) + const textElem = elem.append('text'); + textElem.attr('x', textData.x); + textElem.attr('y', textData.y); + textElem.style('text-anchor', textData.anchor); + textElem.attr('fill', textData.fill); if (typeof textData.class !== 'undefined') { - textElem.attr('class', textData.class) + textElem.attr('class', textData.class); } - const span = textElem.append('tspan') - span.attr('x', textData.x + textData.textMargin * 2) - span.attr('fill', textData.fill) - span.text(nText) + const span = textElem.append('tspan'); + span.attr('x', textData.x + textData.textMargin * 2); + span.attr('fill', textData.fill); + span.text(nText); - return textElem -} + return textElem; +}; -export const drawLabel = function (elem, txtObject) { - function genPoints (x, y, width, height, cut) { - return x + ',' + y + ' ' + - (x + width) + ',' + y + ' ' + - (x + width) + ',' + (y + height - cut) + ' ' + - (x + width - cut * 1.2) + ',' + (y + height) + ' ' + - (x) + ',' + (y + height) +export const drawLabel = function(elem, txtObject) { + function genPoints(x, y, width, height, cut) { + return ( + x + + ',' + + y + + ' ' + + (x + width) + + ',' + + y + + ' ' + + (x + width) + + ',' + + (y + height - cut) + + ' ' + + (x + width - cut * 1.2) + + ',' + + (y + height) + + ' ' + + x + + ',' + + (y + height) + ); } - const polygon = elem.append('polygon') - polygon.attr('points', genPoints(txtObject.x, txtObject.y, 50, 20, 7)) - polygon.attr('class', 'labelBox') + const polygon = elem.append('polygon'); + polygon.attr('points', genPoints(txtObject.x, txtObject.y, 50, 20, 7)); + polygon.attr('class', 'labelBox'); - txtObject.y = txtObject.y + txtObject.labelMargin - txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin - drawText(elem, txtObject) -} + txtObject.y = txtObject.y + txtObject.labelMargin; + txtObject.x = txtObject.x + 0.5 * txtObject.labelMargin; + drawText(elem, txtObject); +}; -let actorCnt = -1 +let actorCnt = -1; /** * Draws an actor in the diagram with the attaced line * @param center - The center of the the actor * @param pos The position if the actor in the liost of actors * @param description The text in the box */ -export const drawActor = function (elem, left, verticalPos, description, conf) { - const center = left + (conf.width / 2) - const g = elem.append('g') +export const drawActor = function(elem, left, verticalPos, description, conf) { + const center = left + conf.width / 2; + const g = elem.append('g'); if (verticalPos === 0) { - actorCnt++ + actorCnt++; g.append('line') .attr('id', 'actor' + actorCnt) .attr('x1', center) @@ -74,43 +90,51 @@ export const drawActor = function (elem, left, verticalPos, description, conf) { .attr('y2', 2000) .attr('class', 'actor-line') .attr('stroke-width', '0.5px') - .attr('stroke', '#999') + .attr('stroke', '#999'); } - const rect = getNoteRect() - rect.x = left - rect.y = verticalPos - rect.fill = '#eaeaea' - rect.width = conf.width - rect.height = conf.height - rect.class = 'actor' - rect.rx = 3 - rect.ry = 3 - drawRect(g, rect) + const rect = getNoteRect(); + rect.x = left; + rect.y = verticalPos; + rect.fill = '#eaeaea'; + rect.width = conf.width; + rect.height = conf.height; + rect.class = 'actor'; + rect.rx = 3; + rect.ry = 3; + drawRect(g, rect); - _drawTextCandidateFunc(conf)(description, g, - rect.x, rect.y, rect.width, rect.height, { 'class': 'actor' }, conf) -} + _drawTextCandidateFunc(conf)( + description, + g, + rect.x, + rect.y, + rect.width, + rect.height, + { class: 'actor' }, + conf + ); +}; -export const anchorElement = function (elem) { - return elem.append('g') -} +export const anchorElement = function(elem) { + return elem.append('g'); +}; /** * Draws an actor in the diagram with the attaced line * @param elem - element to append activation rect * @param bounds - activation box bounds * @param verticalPos - precise y cooridnate of bottom activation box edge */ -export const drawActivation = function (elem, bounds, verticalPos, conf, actorActivations) { - const rect = getNoteRect() - const g = bounds.anchored - rect.x = bounds.startx - rect.y = bounds.starty - rect.class = 'activation' + (actorActivations % 3) // Will evaluate to 0, 1 or 2 - rect.width = bounds.stopx - bounds.startx - rect.height = verticalPos - bounds.starty - drawRect(g, rect) -} +export const drawActivation = function(elem, bounds, verticalPos, conf, actorActivations) { + const rect = getNoteRect(); + const g = bounds.anchored; + rect.x = bounds.startx; + rect.y = bounds.starty; + rect.class = 'activation' + (actorActivations % 3); // Will evaluate to 0, 1 or 2 + rect.width = bounds.stopx - bounds.startx; + rect.height = verticalPos - bounds.starty; + drawRect(g, rect); +}; /** * Draws an actor in the diagram with the attaced line @@ -118,60 +142,61 @@ export const drawActivation = function (elem, bounds, verticalPos, conf, actorAc * @param pos The position if the actor in the list of actors * @param description The text in the box */ -export const drawLoop = function (elem, bounds, labelText, conf) { - const g = elem.append('g') - const drawLoopLine = function (startx, starty, stopx, stopy) { - return g.append('line') +export const drawLoop = function(elem, bounds, labelText, conf) { + const g = elem.append('g'); + const drawLoopLine = function(startx, starty, stopx, stopy) { + return g + .append('line') .attr('x1', startx) .attr('y1', starty) .attr('x2', stopx) .attr('y2', stopy) - .attr('class', 'loopLine') - } - drawLoopLine(bounds.startx, bounds.starty, bounds.stopx, bounds.starty) - drawLoopLine(bounds.stopx, bounds.starty, bounds.stopx, bounds.stopy) - drawLoopLine(bounds.startx, bounds.stopy, bounds.stopx, bounds.stopy) - drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy) + .attr('class', 'loopLine'); + }; + drawLoopLine(bounds.startx, bounds.starty, bounds.stopx, bounds.starty); + drawLoopLine(bounds.stopx, bounds.starty, bounds.stopx, bounds.stopy); + drawLoopLine(bounds.startx, bounds.stopy, bounds.stopx, bounds.stopy); + drawLoopLine(bounds.startx, bounds.starty, bounds.startx, bounds.stopy); if (typeof bounds.sections !== 'undefined') { - bounds.sections.forEach(function (item) { - drawLoopLine(bounds.startx, item, bounds.stopx, item).style('stroke-dasharray', '3, 3') - }) + bounds.sections.forEach(function(item) { + drawLoopLine(bounds.startx, item, bounds.stopx, item).style('stroke-dasharray', '3, 3'); + }); } - let txt = getTextObj() - txt.text = labelText - txt.x = bounds.startx - txt.y = bounds.starty - txt.labelMargin = 1.5 * 10 // This is the small box that says "loop" - txt.class = 'labelText' // Its size & position are fixed. + let txt = getTextObj(); + txt.text = labelText; + txt.x = bounds.startx; + txt.y = bounds.starty; + txt.labelMargin = 1.5 * 10; // This is the small box that says "loop" + txt.class = 'labelText'; // Its size & position are fixed. - drawLabel(g, txt) + drawLabel(g, txt); - txt = getTextObj() - txt.text = '[ ' + bounds.title + ' ]' - txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2 - txt.y = bounds.starty + 1.5 * conf.boxMargin - txt.anchor = 'middle' - txt.class = 'loopText' + txt = getTextObj(); + txt.text = '[ ' + bounds.title + ' ]'; + txt.x = bounds.startx + (bounds.stopx - bounds.startx) / 2; + txt.y = bounds.starty + 1.5 * conf.boxMargin; + txt.anchor = 'middle'; + txt.class = 'loopText'; - drawText(g, txt) + drawText(g, txt); if (typeof bounds.sectionTitles !== 'undefined') { - bounds.sectionTitles.forEach(function (item, idx) { + bounds.sectionTitles.forEach(function(item, idx) { if (item !== '') { - txt.text = '[ ' + item + ' ]' - txt.y = bounds.sections[idx] + 1.5 * conf.boxMargin - drawText(g, txt) + txt.text = '[ ' + item + ' ]'; + txt.y = bounds.sections[idx] + 1.5 * conf.boxMargin; + drawText(g, txt); } - }) + }); } -} +}; /** * Draws a background rectangle * @param color - The fill color for the background */ -export const drawBackgroundRect = function (elem, bounds) { +export const drawBackgroundRect = function(elem, bounds) { const rectElem = drawRect(elem, { x: bounds.startx, y: bounds.starty, @@ -179,14 +204,16 @@ export const drawBackgroundRect = function (elem, bounds) { height: bounds.stopy - bounds.starty, fill: bounds.fill, class: 'rect' - }) - rectElem.lower() -} + }); + rectElem.lower(); +}; /** * Setup arrow head and define the marker. The result is appended to the svg. */ -export const insertArrowHead = function (elem) { - elem.append('defs').append('marker') +export const insertArrowHead = function(elem) { + elem + .append('defs') + .append('marker') .attr('id', 'arrowhead') .attr('refX', 5) .attr('refY', 2) @@ -194,13 +221,15 @@ export const insertArrowHead = function (elem) { .attr('markerHeight', 4) .attr('orient', 'auto') .append('path') - .attr('d', 'M 0,0 V 4 L6,2 Z') // this is actual shape for arrowhead -} + .attr('d', 'M 0,0 V 4 L6,2 Z'); // this is actual shape for arrowhead +}; /** * Setup node number. The result is appended to the svg. */ -export const insertSequenceNumber = function (elem) { - elem.append('defs').append('marker') +export const insertSequenceNumber = function(elem) { + elem + .append('defs') + .append('marker') .attr('id', 'sequencenumber') .attr('refX', 15) .attr('refY', 15) @@ -210,45 +239,48 @@ export const insertSequenceNumber = function (elem) { .append('circle') .attr('cx', 15) .attr('cy', 15) - .attr('r', 6) - // .style("fill", '#f00'); -} + .attr('r', 6); + // .style("fill", '#f00'); +}; /** * Setup arrow head and define the marker. The result is appended to the svg. */ -export const insertArrowCrossHead = function (elem) { - const defs = elem.append('defs') - const marker = defs.append('marker') +export const insertArrowCrossHead = function(elem) { + const defs = elem.append('defs'); + const marker = defs + .append('marker') .attr('id', 'crosshead') .attr('markerWidth', 15) .attr('markerHeight', 8) .attr('orient', 'auto') .attr('refX', 16) - .attr('refY', 4) + .attr('refY', 4); // The arrow - marker.append('path') + marker + .append('path') .attr('fill', 'black') .attr('stroke', '#000000') - .style('stroke-dasharray', ('0, 0')) + .style('stroke-dasharray', '0, 0') .attr('stroke-width', '1px') - .attr('d', 'M 9,2 V 6 L16,4 Z') + .attr('d', 'M 9,2 V 6 L16,4 Z'); // The cross - marker.append('path') + marker + .append('path') .attr('fill', 'none') .attr('stroke', '#000000') - .style('stroke-dasharray', ('0, 0')) + .style('stroke-dasharray', '0, 0') .attr('stroke-width', '1px') - .attr('d', 'M 0,1 L 6,7 M 6,1 L 0,7') + .attr('d', 'M 0,1 L 6,7 M 6,1 L 0,7'); // this is actual shape for arrowhead -} +}; -export const getTextObj = function () { +export const getTextObj = function() { const txt = { x: 0, y: 0, - 'fill': undefined, + fill: undefined, 'text-anchor': 'start', style: '#666', width: 100, @@ -256,11 +288,11 @@ export const getTextObj = function () { textMargin: 0, rx: 0, ry: 0 - } - return txt -} + }; + return txt; +}; -export const getNoteRect = function () { +export const getNoteRect = function() { const rect = { x: 0, y: 0, @@ -271,72 +303,87 @@ export const getNoteRect = function () { height: 100, rx: 0, ry: 0 - } - return rect -} + }; + return rect; +}; -const _drawTextCandidateFunc = (function () { - function byText (content, g, x, y, width, height, textAttrs) { - const text = g.append('text') - .attr('x', x + width / 2).attr('y', y + height / 2 + 5) +const _drawTextCandidateFunc = (function() { + function byText(content, g, x, y, width, height, textAttrs) { + const text = g + .append('text') + .attr('x', x + width / 2) + .attr('y', y + height / 2 + 5) .style('text-anchor', 'middle') - .text(content) - _setTextAttrs(text, textAttrs) + .text(content); + _setTextAttrs(text, textAttrs); } - function byTspan (content, g, x, y, width, height, textAttrs, conf) { - const { actorFontSize, actorFontFamily } = conf + function byTspan(content, g, x, y, width, height, textAttrs, conf) { + const { actorFontSize, actorFontFamily } = conf; - const lines = content.split(//ig) + const lines = content.split(//gi); for (let i = 0; i < lines.length; i++) { - const dy = (i * actorFontSize) - (actorFontSize * (lines.length - 1) / 2) - const text = g.append('text') - .attr('x', x + width / 2).attr('y', y) + const dy = i * actorFontSize - (actorFontSize * (lines.length - 1)) / 2; + const text = g + .append('text') + .attr('x', x + width / 2) + .attr('y', y) .style('text-anchor', 'middle') .style('font-size', actorFontSize) - .style('font-family', actorFontFamily) - text.append('tspan') - .attr('x', x + width / 2).attr('dy', dy) - .text(lines[i]) + .style('font-family', actorFontFamily); + text + .append('tspan') + .attr('x', x + width / 2) + .attr('dy', dy) + .text(lines[i]); - text.attr('y', y + height / 2.0) + text + .attr('y', y + height / 2.0) .attr('dominant-baseline', 'central') - .attr('alignment-baseline', 'central') + .attr('alignment-baseline', 'central'); - _setTextAttrs(text, textAttrs) + _setTextAttrs(text, textAttrs); } } - function byFo (content, g, x, y, width, height, textAttrs, conf) { - const s = g.append('switch') - const f = s.append('foreignObject') - .attr('x', x).attr('y', y) - .attr('width', width).attr('height', height) + function byFo(content, g, x, y, width, height, textAttrs, conf) { + const s = g.append('switch'); + const f = s + .append('foreignObject') + .attr('x', x) + .attr('y', y) + .attr('width', width) + .attr('height', height); - const text = f.append('div').style('display', 'table') - .style('height', '100%').style('width', '100%') + const text = f + .append('div') + .style('display', 'table') + .style('height', '100%') + .style('width', '100%'); - text.append('div').style('display', 'table-cell') - .style('text-align', 'center').style('vertical-align', 'middle') - .text(content) + text + .append('div') + .style('display', 'table-cell') + .style('text-align', 'center') + .style('vertical-align', 'middle') + .text(content); - byTspan(content, s, x, y, width, height, textAttrs, conf) - _setTextAttrs(text, textAttrs) + byTspan(content, s, x, y, width, height, textAttrs, conf); + _setTextAttrs(text, textAttrs); } - function _setTextAttrs (toText, fromTextAttrsDict) { + function _setTextAttrs(toText, fromTextAttrsDict) { for (const key in fromTextAttrsDict) { if (fromTextAttrsDict.hasOwnProperty(key)) { - toText.attr(key, fromTextAttrsDict[key]) + toText.attr(key, fromTextAttrsDict[key]); } } } - return function (conf) { - return conf.textPlacement === 'fo' ? byFo : ( - conf.textPlacement === 'old' ? byText : byTspan) - } -})() + return function(conf) { + return conf.textPlacement === 'fo' ? byFo : conf.textPlacement === 'old' ? byText : byTspan; + }; +})(); export default { drawRect, @@ -352,4 +399,4 @@ export default { insertArrowCrossHead, getTextObj, getNoteRect -} +}; diff --git a/src/diagrams/sequence/svgDraw.spec.js b/src/diagrams/sequence/svgDraw.spec.js index efb541e78..c99b9b95b 100644 --- a/src/diagrams/sequence/svgDraw.spec.js +++ b/src/diagrams/sequence/svgDraw.spec.js @@ -1,11 +1,11 @@ /* eslint-env jasmine */ -const svgDraw = require('./svgDraw') -const { MockD3 } = require('d3') +const svgDraw = require('./svgDraw'); +const { MockD3 } = require('d3'); -describe('svgDraw', function () { - describe('drawRect', function () { - it('it should append a rectangle', function () { - const svg = MockD3('svg') +describe('svgDraw', function() { + describe('drawRect', function() { + it('it should append a rectangle', function() { + const svg = MockD3('svg'); svgDraw.drawRect(svg, { x: 10, y: 10, @@ -16,22 +16,22 @@ describe('svgDraw', function () { rx: '10', ry: '10', class: 'unitTestRectangleClass' - }) - expect(svg.__children.length).toBe(1) - const rect = svg.__children[0] - expect(rect.__name).toBe('rect') - expect(rect.attr).toHaveBeenCalledWith('x', 10) - expect(rect.attr).toHaveBeenCalledWith('y', 10) - expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc') - expect(rect.attr).toHaveBeenCalledWith('stroke', 'red') - expect(rect.attr).toHaveBeenCalledWith('width', '20') - expect(rect.attr).toHaveBeenCalledWith('height', '20') - expect(rect.attr).toHaveBeenCalledWith('rx', '10') - expect(rect.attr).toHaveBeenCalledWith('ry', '10') - expect(rect.attr).toHaveBeenCalledWith('class', 'unitTestRectangleClass') - }) + }); + expect(svg.__children.length).toBe(1); + const rect = svg.__children[0]; + expect(rect.__name).toBe('rect'); + expect(rect.attr).toHaveBeenCalledWith('x', 10); + expect(rect.attr).toHaveBeenCalledWith('y', 10); + expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc'); + expect(rect.attr).toHaveBeenCalledWith('stroke', 'red'); + expect(rect.attr).toHaveBeenCalledWith('width', '20'); + expect(rect.attr).toHaveBeenCalledWith('height', '20'); + expect(rect.attr).toHaveBeenCalledWith('rx', '10'); + expect(rect.attr).toHaveBeenCalledWith('ry', '10'); + expect(rect.attr).toHaveBeenCalledWith('class', 'unitTestRectangleClass'); + }); it('it should not add the class attribute if a class isn`t provided', () => { - const svg = MockD3('svg') + const svg = MockD3('svg'); svgDraw.drawRect(svg, { x: 10, y: 10, @@ -41,17 +41,17 @@ describe('svgDraw', function () { height: '20', rx: '10', ry: '10' - }) - expect(svg.__children.length).toBe(1) - const rect = svg.__children[0] - expect(rect.__name).toBe('rect') - expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc') - expect(rect.attr).not.toHaveBeenCalledWith('class', expect.anything()) - }) - }) - describe('drawBackgroundRect', function () { - it('it should append a rect before the previous element within a given bound', function () { - const svg = MockD3('svg') + }); + expect(svg.__children.length).toBe(1); + const rect = svg.__children[0]; + expect(rect.__name).toBe('rect'); + expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc'); + expect(rect.attr).not.toHaveBeenCalledWith('class', expect.anything()); + }); + }); + describe('drawBackgroundRect', function() { + it('it should append a rect before the previous element within a given bound', function() { + const svg = MockD3('svg'); const boundingRect = { startx: 50, starty: 200, @@ -59,18 +59,18 @@ describe('svgDraw', function () { stopy: 260, title: undefined, fill: '#ccc' - } - svgDraw.drawBackgroundRect(svg, boundingRect) - expect(svg.__children.length).toBe(1) - const rect = svg.__children[0] - expect(rect.__name).toBe('rect') - expect(rect.attr).toHaveBeenCalledWith('x', 50) - expect(rect.attr).toHaveBeenCalledWith('y', 200) - expect(rect.attr).toHaveBeenCalledWith('width', 100) - expect(rect.attr).toHaveBeenCalledWith('height', 60) - expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc') - expect(rect.attr).toHaveBeenCalledWith('class', 'rect') - expect(rect.lower).toHaveBeenCalled() - }) - }) -}) + }; + svgDraw.drawBackgroundRect(svg, boundingRect); + expect(svg.__children.length).toBe(1); + const rect = svg.__children[0]; + expect(rect.__name).toBe('rect'); + expect(rect.attr).toHaveBeenCalledWith('x', 50); + expect(rect.attr).toHaveBeenCalledWith('y', 200); + expect(rect.attr).toHaveBeenCalledWith('width', 100); + expect(rect.attr).toHaveBeenCalledWith('height', 60); + expect(rect.attr).toHaveBeenCalledWith('fill', '#ccc'); + expect(rect.attr).toHaveBeenCalledWith('class', 'rect'); + expect(rect.lower).toHaveBeenCalled(); + }); + }); +}); From ad5669b52352edc973624f620b95e8ea6f6f92f2 Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:55:10 -0700 Subject: [PATCH 03/13] #931 Aligning code standard --- src/diagrams/sequence/sequenceDb.js | 190 +-- src/diagrams/sequence/sequenceDiagram.spec.js | 1422 +++++++++-------- src/diagrams/sequence/sequenceRenderer.js | 684 ++++---- 3 files changed, 1212 insertions(+), 1084 deletions(-) diff --git a/src/diagrams/sequence/sequenceDb.js b/src/diagrams/sequence/sequenceDb.js index e531ed2f9..050691a6c 100644 --- a/src/diagrams/sequence/sequenceDb.js +++ b/src/diagrams/sequence/sequenceDb.js @@ -1,51 +1,53 @@ -import { logger } from '../../logger' +import { logger } from '../../logger'; -let actors = {} -let messages = [] -const notes = [] -let title = '' +let actors = {}; +let messages = []; +const notes = []; +let title = ''; -export const addActor = function (id, name, description) { +export const addActor = function(id, name, description) { // Don't allow description nulling - const old = actors[id] - if (old && name === old.name && description == null) return + const old = actors[id]; + if (old && name === old.name && description == null) return; // Don't allow null descriptions, either - if (description == null) description = name + if (description == null) description = name; - actors[id] = { name: name, description: description } -} + actors[id] = { name: name, description: description }; +}; -export const addMessage = function (idFrom, idTo, message, answer) { - messages.push({ from: idFrom, to: idTo, message: message, answer: answer }) -} +export const addMessage = function(idFrom, idTo, message, answer) { + messages.push({ from: idFrom, to: idTo, message: message, answer: answer }); +}; -export const addSignal = function (idFrom, idTo, message, messageType) { - logger.debug('Adding message from=' + idFrom + ' to=' + idTo + ' message=' + message + ' type=' + messageType) - messages.push({ from: idFrom, to: idTo, message: message, type: messageType }) -} +export const addSignal = function(idFrom, idTo, message, messageType) { + logger.debug( + 'Adding message from=' + idFrom + ' to=' + idTo + ' message=' + message + ' type=' + messageType + ); + messages.push({ from: idFrom, to: idTo, message: message, type: messageType }); +}; -export const getMessages = function () { - return messages -} +export const getMessages = function() { + return messages; +}; -export const getActors = function () { - return actors -} -export const getActor = function (id) { - return actors[id] -} -export const getActorKeys = function () { - return Object.keys(actors) -} -export const getTitle = function () { - return title -} +export const getActors = function() { + return actors; +}; +export const getActor = function(id) { + return actors[id]; +}; +export const getActorKeys = function() { + return Object.keys(actors); +}; +export const getTitle = function() { + return title; +}; -export const clear = function () { - actors = {} - messages = [] -} +export const clear = function() { + actors = {}; + messages = []; +}; export const LINETYPE = { SOLID: 0, @@ -69,97 +71,103 @@ export const LINETYPE = { PAR_END: 21, RECT_START: 22, RECT_END: 23 -} +}; export const ARROWTYPE = { FILLED: 0, OPEN: 1 -} +}; export const PLACEMENT = { LEFTOF: 0, RIGHTOF: 1, OVER: 2 -} +}; -export const addNote = function (actor, placement, message) { - const note = { actor: actor, placement: placement, message: message } +export const addNote = function(actor, placement, message) { + const note = { actor: actor, placement: placement, message: message }; // Coerce actor into a [to, from, ...] array - const actors = [].concat(actor, actor) + const actors = [].concat(actor, actor); - notes.push(note) - messages.push({ from: actors[0], to: actors[1], message: message, type: LINETYPE.NOTE, placement: placement }) -} + notes.push(note); + messages.push({ + from: actors[0], + to: actors[1], + message: message, + type: LINETYPE.NOTE, + placement: placement + }); +}; -export const setTitle = function (titleText) { - title = titleText -} +export const setTitle = function(titleText) { + title = titleText; +}; -export const apply = function (param) { +export const apply = function(param) { if (param instanceof Array) { - param.forEach(function (item) { - apply(item) - }) + param.forEach(function(item) { + apply(item); + }); } else { switch (param.type) { case 'addActor': - addActor(param.actor, param.actor, param.description) - break + addActor(param.actor, param.actor, param.description); + break; case 'activeStart': - addSignal(param.actor, undefined, undefined, param.signalType) - break + addSignal(param.actor, undefined, undefined, param.signalType); + break; case 'activeEnd': - addSignal(param.actor, undefined, undefined, param.signalType) - break + addSignal(param.actor, undefined, undefined, param.signalType); + break; case 'addNote': - addNote(param.actor, param.placement, param.text) - break + addNote(param.actor, param.placement, param.text); + break; case 'addMessage': - addSignal(param.from, param.to, param.msg, param.signalType) - break + addSignal(param.from, param.to, param.msg, param.signalType); + break; case 'loopStart': - addSignal(undefined, undefined, param.loopText, param.signalType) - break + addSignal(undefined, undefined, param.loopText, param.signalType); + break; case 'loopEnd': - addSignal(undefined, undefined, undefined, param.signalType) - break + addSignal(undefined, undefined, undefined, param.signalType); + break; case 'rectStart': - addSignal(undefined, undefined, param.color, param.signalType) - break + addSignal(undefined, undefined, param.color, param.signalType); + break; case 'rectEnd': - addSignal(undefined, undefined, undefined, param.signalType) - break + addSignal(undefined, undefined, undefined, param.signalType); + break; case 'optStart': - addSignal(undefined, undefined, param.optText, param.signalType) - break + addSignal(undefined, undefined, param.optText, param.signalType); + break; case 'optEnd': - addSignal(undefined, undefined, undefined, param.signalType) - break + addSignal(undefined, undefined, undefined, param.signalType); + break; case 'altStart': - addSignal(undefined, undefined, param.altText, param.signalType) - break + addSignal(undefined, undefined, param.altText, param.signalType); + break; case 'else': - addSignal(undefined, undefined, param.altText, param.signalType) - break + addSignal(undefined, undefined, param.altText, param.signalType); + break; case 'altEnd': - addSignal(undefined, undefined, undefined, param.signalType) - break + addSignal(undefined, undefined, undefined, param.signalType); + break; case 'setTitle': - setTitle(param.text) - break + setTitle(param.text); + break; case 'parStart': - addSignal(undefined, undefined, param.parText, param.signalType) - break + addSignal(undefined, undefined, param.parText, param.signalType); + break; case 'and': - addSignal(undefined, undefined, param.parText, param.signalType) - break + addSignal(undefined, undefined, param.parText, param.signalType); + break; case 'parEnd': - addSignal(undefined, undefined, undefined, param.signalType) - break + addSignal(undefined, undefined, undefined, param.signalType); + break; } } -} +}; export default { addActor, @@ -177,4 +185,4 @@ export default { addNote, setTitle, apply -} +}; diff --git a/src/diagrams/sequence/sequenceDiagram.spec.js b/src/diagrams/sequence/sequenceDiagram.spec.js index d9039e6c5..2ed1c411c 100644 --- a/src/diagrams/sequence/sequenceDiagram.spec.js +++ b/src/diagrams/sequence/sequenceDiagram.spec.js @@ -1,307 +1,316 @@ /* eslint-env jasmine */ -import { parser } from './parser/sequenceDiagram' -import sequenceDb from './sequenceDb' -import renderer from './sequenceRenderer' +import { parser } from './parser/sequenceDiagram'; +import sequenceDb from './sequenceDb'; +import renderer from './sequenceRenderer'; -function addConf (conf, key, value) { +function addConf(conf, key, value) { if (value !== undefined) { - conf[key] = value + conf[key] = value; } - return conf + return conf; } -describe('when parsing a sequenceDiagram', function () { - beforeEach(function () { - parser.yy = sequenceDb - parser.yy.clear() - }) - it('it should handle a sequenceDiagram defintion', function () { - const str = 'sequenceDiagram\n' + +describe('when parsing a sequenceDiagram', function() { + beforeEach(function() { + parser.yy = sequenceDb; + parser.yy.clear(); + }); + it('it should handle a sequenceDiagram defintion', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob:Hello Bob, how are you?\n' + 'Note right of Bob: Bob thinks\n' + - 'Bob-->Alice: I am good thanks!' + 'Bob-->Alice: I am good thanks!'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(3) - expect(messages[0].from).toBe('Alice') - expect(messages[2].from).toBe('Bob') - }) - it('it should handle a sequenceDiagram definition with a title', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(3); + expect(messages[0].from).toBe('Alice'); + expect(messages[2].from).toBe('Bob'); + }); + it('it should handle a sequenceDiagram definition with a title', function() { + const str = + 'sequenceDiagram\n' + 'title: Diagram Title\n' + 'Alice->Bob:Hello Bob, how are you?\n' + 'Note right of Bob: Bob thinks\n' + - 'Bob-->Alice: I am good thanks!' + 'Bob-->Alice: I am good thanks!'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() - const title = parser.yy.getTitle() + const messages = parser.yy.getMessages(); + const title = parser.yy.getTitle(); - expect(messages.length).toBe(3) - expect(messages[0].from).toBe('Alice') - expect(messages[2].from).toBe('Bob') - expect(title).toBe('Diagram Title') - }) - it('it should space in actor names', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(3); + expect(messages[0].from).toBe('Alice'); + expect(messages[2].from).toBe('Bob'); + expect(title).toBe('Diagram Title'); + }); + it('it should space in actor names', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob:Hello Bob, how are - you?\n' + - 'Bob-->Alice: I am good thanks!' + 'Bob-->Alice: I am good thanks!'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(2) - expect(messages[0].from).toBe('Alice') - expect(messages[1].from).toBe('Bob') - }) - it('it should alias participants', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(2); + expect(messages[0].from).toBe('Alice'); + expect(messages[1].from).toBe('Bob'); + }); + it('it should alias participants', function() { + const str = + 'sequenceDiagram\n' + 'participant A as Alice\n' + 'participant B as Bob\n' + 'A->B:Hello Bob, how are you?\n' + - 'B-->A: I am good thanks!' + 'B-->A: I am good thanks!'; - parser.parse(str) + parser.parse(str); - const actors = parser.yy.getActors() - expect(Object.keys(actors)).toEqual(['A', 'B']) - expect(actors.A.description).toBe('Alice') - expect(actors.B.description).toBe('Bob') + const actors = parser.yy.getActors(); + expect(Object.keys(actors)).toEqual(['A', 'B']); + expect(actors.A.description).toBe('Alice'); + expect(actors.B.description).toBe('Bob'); - const messages = parser.yy.getMessages() - expect(messages.length).toBe(2) - expect(messages[0].from).toBe('A') - expect(messages[1].from).toBe('B') - }) - it('it should handle in async messages', function () { - const str = 'sequenceDiagram\n' + - 'Alice-xBob:Hello Bob, how are you?' + const messages = parser.yy.getMessages(); + expect(messages.length).toBe(2); + expect(messages[0].from).toBe('A'); + expect(messages[1].from).toBe('B'); + }); + it('it should handle in async messages', function() { + const str = 'sequenceDiagram\n' + 'Alice-xBob:Hello Bob, how are you?'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - expect(actors.Bob.description).toBe('Bob') + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + expect(actors.Bob.description).toBe('Bob'); - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(1) - expect(messages[0].type).toBe(parser.yy.LINETYPE.SOLID_CROSS) - }) - it('it should handle in async dotted messages', function () { - const str = 'sequenceDiagram\n' + - 'Alice--xBob:Hello Bob, how are you?' + expect(messages.length).toBe(1); + expect(messages[0].type).toBe(parser.yy.LINETYPE.SOLID_CROSS); + }); + it('it should handle in async dotted messages', function() { + const str = 'sequenceDiagram\n' + 'Alice--xBob:Hello Bob, how are you?'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - expect(actors.Bob.description).toBe('Bob') + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + expect(actors.Bob.description).toBe('Bob'); - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(1) - expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED_CROSS) - }) - it('it should handle in arrow messages', function () { - const str = 'sequenceDiagram\n' + - 'Alice->>Bob:Hello Bob, how are you?' + expect(messages.length).toBe(1); + expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED_CROSS); + }); + it('it should handle in arrow messages', function() { + const str = 'sequenceDiagram\n' + 'Alice->>Bob:Hello Bob, how are you?'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - expect(actors.Bob.description).toBe('Bob') + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + expect(actors.Bob.description).toBe('Bob'); - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(1) - expect(messages[0].type).toBe(parser.yy.LINETYPE.SOLID) - }) - it('it should handle in arrow messages', function () { - const str = 'sequenceDiagram\n' + - 'Alice-->>Bob:Hello Bob, how are you?' + expect(messages.length).toBe(1); + expect(messages[0].type).toBe(parser.yy.LINETYPE.SOLID); + }); + it('it should handle in arrow messages', function() { + const str = 'sequenceDiagram\n' + 'Alice-->>Bob:Hello Bob, how are you?'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - expect(actors.Bob.description).toBe('Bob') + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + expect(actors.Bob.description).toBe('Bob'); - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(1) - expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED) - }) - it('it should handle actor activation', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(1); + expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED); + }); + it('it should handle actor activation', function() { + const str = + 'sequenceDiagram\n' + 'Alice-->>Bob:Hello Bob, how are you?\n' + 'activate Bob\n' + - 'Bob-->>Alice:Hello Alice, I\'m fine and you?\n' + - 'deactivate Bob' + "Bob-->>Alice:Hello Alice, I'm fine and you?\n" + + 'deactivate Bob'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - expect(actors.Bob.description).toBe('Bob') + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + expect(actors.Bob.description).toBe('Bob'); - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(4) - expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED) - expect(messages[1].type).toBe(parser.yy.LINETYPE.ACTIVE_START) - expect(messages[1].from.actor).toBe('Bob') - expect(messages[2].type).toBe(parser.yy.LINETYPE.DOTTED) - expect(messages[3].type).toBe(parser.yy.LINETYPE.ACTIVE_END) - expect(messages[3].from.actor).toBe('Bob') - }) - it('it should handle actor one line notation activation', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(4); + expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED); + expect(messages[1].type).toBe(parser.yy.LINETYPE.ACTIVE_START); + expect(messages[1].from.actor).toBe('Bob'); + expect(messages[2].type).toBe(parser.yy.LINETYPE.DOTTED); + expect(messages[3].type).toBe(parser.yy.LINETYPE.ACTIVE_END); + expect(messages[3].from.actor).toBe('Bob'); + }); + it('it should handle actor one line notation activation', function() { + const str = + 'sequenceDiagram\n' + 'Alice-->>+Bob:Hello Bob, how are you?\n' + - 'Bob-->>- Alice:Hello Alice, I\'m fine and you?' + "Bob-->>- Alice:Hello Alice, I'm fine and you?"; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - expect(actors.Bob.description).toBe('Bob') + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + expect(actors.Bob.description).toBe('Bob'); - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(4) - expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED) - expect(messages[1].type).toBe(parser.yy.LINETYPE.ACTIVE_START) - expect(messages[1].from.actor).toBe('Bob') - expect(messages[2].type).toBe(parser.yy.LINETYPE.DOTTED) - expect(messages[3].type).toBe(parser.yy.LINETYPE.ACTIVE_END) - expect(messages[3].from.actor).toBe('Bob') - }) - it('it should handle stacked activations', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(4); + expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED); + expect(messages[1].type).toBe(parser.yy.LINETYPE.ACTIVE_START); + expect(messages[1].from.actor).toBe('Bob'); + expect(messages[2].type).toBe(parser.yy.LINETYPE.DOTTED); + expect(messages[3].type).toBe(parser.yy.LINETYPE.ACTIVE_END); + expect(messages[3].from.actor).toBe('Bob'); + }); + it('it should handle stacked activations', function() { + const str = + 'sequenceDiagram\n' + 'Alice-->>+Bob:Hello Bob, how are you?\n' + 'Bob-->>+Carol:Carol, let me introduce Alice?\n' + 'Bob-->>- Alice:Hello Alice, please meet Carol?\n' + - 'Carol->>- Bob:Oh Bob, I\'m so happy to be here!' + "Carol->>- Bob:Oh Bob, I'm so happy to be here!"; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - expect(actors.Bob.description).toBe('Bob') + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + expect(actors.Bob.description).toBe('Bob'); - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(8) - expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED) - expect(messages[1].type).toBe(parser.yy.LINETYPE.ACTIVE_START) - expect(messages[1].from.actor).toBe('Bob') - expect(messages[2].type).toBe(parser.yy.LINETYPE.DOTTED) - expect(messages[3].type).toBe(parser.yy.LINETYPE.ACTIVE_START) - expect(messages[3].from.actor).toBe('Carol') - expect(messages[5].type).toBe(parser.yy.LINETYPE.ACTIVE_END) - expect(messages[5].from.actor).toBe('Bob') - expect(messages[7].type).toBe(parser.yy.LINETYPE.ACTIVE_END) - expect(messages[7].from.actor).toBe('Carol') - }) - it('it should handle comments in a sequenceDiagram', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(8); + expect(messages[0].type).toBe(parser.yy.LINETYPE.DOTTED); + expect(messages[1].type).toBe(parser.yy.LINETYPE.ACTIVE_START); + expect(messages[1].from.actor).toBe('Bob'); + expect(messages[2].type).toBe(parser.yy.LINETYPE.DOTTED); + expect(messages[3].type).toBe(parser.yy.LINETYPE.ACTIVE_START); + expect(messages[3].from.actor).toBe('Carol'); + expect(messages[5].type).toBe(parser.yy.LINETYPE.ACTIVE_END); + expect(messages[5].from.actor).toBe('Bob'); + expect(messages[7].type).toBe(parser.yy.LINETYPE.ACTIVE_END); + expect(messages[7].from.actor).toBe('Carol'); + }); + it('it should handle comments in a sequenceDiagram', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + - 'Bob-->Alice: I am good thanks!' + 'Bob-->Alice: I am good thanks!'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(3) - expect(messages[0].from).toBe('Alice') - expect(messages[2].from).toBe('Bob') - }) - it('it should handle new lines in a sequenceDiagram', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(3); + expect(messages[0].from).toBe('Alice'); + expect(messages[2].from).toBe('Bob'); + }); + it('it should handle new lines in a sequenceDiagram', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + - 'Bob-->Alice: I am good thanks!\n' + 'Bob-->Alice: I am good thanks!\n'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(3) - expect(messages[0].from).toBe('Alice') - expect(messages[2].from).toBe('Bob') - }) - it('it should handle semicolons', function () { - const str = 'sequenceDiagram;' + + expect(messages.length).toBe(3); + expect(messages[0].from).toBe('Alice'); + expect(messages[2].from).toBe('Bob'); + }); + it('it should handle semicolons', function() { + const str = + 'sequenceDiagram;' + 'Alice->Bob: Hello Bob, how are you?;' + 'Note right of Bob: Bob thinks;' + - 'Bob-->Alice: I am good thanks!;' + 'Bob-->Alice: I am good thanks!;'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(3) - expect(messages[0].from).toBe('Alice') - expect(messages[2].from).toBe('Bob') - }) - it('it should handle one leading space in lines in a sequenceDiagram', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(3); + expect(messages[0].from).toBe('Alice'); + expect(messages[2].from).toBe('Bob'); + }); + it('it should handle one leading space in lines in a sequenceDiagram', function() { + const str = + 'sequenceDiagram\n' + ' Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + - 'Bob-->Alice: I am good thanks!' + 'Bob-->Alice: I am good thanks!'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(3) - expect(messages[0].from).toBe('Alice') - expect(messages[2].from).toBe('Bob') - }) - it('it should handle several leading spaces in lines in a sequenceDiagram', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(3); + expect(messages[0].from).toBe('Alice'); + expect(messages[2].from).toBe('Bob'); + }); + it('it should handle several leading spaces in lines in a sequenceDiagram', function() { + const str = + 'sequenceDiagram\n' + ' Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + - 'Bob-->Alice: I am good thanks!' + 'Bob-->Alice: I am good thanks!'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(3) - expect(messages[0].from).toBe('Alice') - expect(messages[2].from).toBe('Bob') - }) - it('it should handle several leading spaces in lines in a sequenceDiagram', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(3); + expect(messages[0].from).toBe('Alice'); + expect(messages[2].from).toBe('Bob'); + }); + it('it should handle several leading spaces in lines in a sequenceDiagram', function() { + const str = + 'sequenceDiagram\n' + 'participant Alice\n' + 'participant Bob\n' + 'Alice->John: Hello John, how are you?\n' + @@ -311,65 +320,66 @@ describe('when parsing a sequenceDiagram', function () { 'Note right of John: Rational thoughts
prevail...\n' + ' John-->Alice: Great!\n' + ' John->Bob: How about you?\n' + - 'Bob-->John: Jolly good!' + 'Bob-->John: Jolly good!'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(8) - expect(messages[0].from).toBe('Alice') - expect(messages[2].from).toBe('John') - }) - it('it should handle notes over a single actor', function () { - const str = 'sequenceDiagram\n' + - 'Alice->Bob: Hello Bob, how are you?\n' + - 'Note over Bob: Bob thinks\n' + expect(messages.length).toBe(8); + expect(messages[0].from).toBe('Alice'); + expect(messages[2].from).toBe('John'); + }); + it('it should handle notes over a single actor', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note over Bob: Bob thinks\n'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].from).toBe('Bob') - expect(messages[1].to).toBe('Bob') - }) - it('it should handle notes over multiple actors', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].from).toBe('Bob'); + expect(messages[1].to).toBe('Bob'); + }); + it('it should handle notes over multiple actors', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note over Alice,Bob: confusion\n' + - 'Note over Bob,Alice: resolution\n' + 'Note over Bob,Alice: resolution\n'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].from).toBe('Alice') - expect(messages[1].to).toBe('Bob') - expect(messages[2].from).toBe('Bob') - expect(messages[2].to).toBe('Alice') - }) - it('it should handle loop statements', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].from).toBe('Alice'); + expect(messages[1].to).toBe('Bob'); + expect(messages[2].from).toBe('Bob'); + expect(messages[2].to).toBe('Alice'); + }); + it('it should handle loop statements', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'loop Multiple happy responses\n\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(5) - expect(messages[0].from).toBe('Alice') - expect(messages[1].from).toBe('Bob') - }) - it('it should add a rect around sequence', function () { + expect(messages.length).toBe(5); + expect(messages[0].from).toBe('Alice'); + expect(messages[1].from).toBe('Bob'); + }); + it('it should add a rect around sequence', function() { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -378,22 +388,22 @@ describe('when parsing a sequenceDiagram', function () { Note right of Bob: Bob thinks Bob-->Alice: I am good thanks end - ` + `; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() - expect(messages[1].type).toEqual(parser.yy.LINETYPE.RECT_START) - expect(messages[1].message).toBe('rgb(200, 255, 200)') - expect(messages[2].type).toEqual(parser.yy.LINETYPE.NOTE) - expect(messages[3].type).toEqual(parser.yy.LINETYPE.DOTTED_OPEN) - expect(messages[4].type).toEqual(parser.yy.LINETYPE.RECT_END) - }) + const messages = parser.yy.getMessages(); + expect(messages[1].type).toEqual(parser.yy.LINETYPE.RECT_START); + expect(messages[1].message).toBe('rgb(200, 255, 200)'); + expect(messages[2].type).toEqual(parser.yy.LINETYPE.NOTE); + expect(messages[3].type).toEqual(parser.yy.LINETYPE.DOTTED_OPEN); + expect(messages[4].type).toEqual(parser.yy.LINETYPE.RECT_END); + }); - it('it should allow for nested rects', function () { + it('it should allow for nested rects', function() { const str = ` sequenceDiagram Alice->Bob: Hello Bob, how are you? @@ -404,44 +414,46 @@ describe('when parsing a sequenceDiagram', function () { end Bob-->Alice: I am good thanks end - ` - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + `; + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() - expect(messages[1].type).toEqual(parser.yy.LINETYPE.RECT_START) - expect(messages[1].message).toBe('rgb(200, 255, 200)') - expect(messages[2].type).toEqual(parser.yy.LINETYPE.RECT_START) - expect(messages[2].message).toBe('rgb(0, 0, 0)') - expect(messages[3].type).toEqual(parser.yy.LINETYPE.NOTE) - expect(messages[4].type).toEqual(parser.yy.LINETYPE.RECT_END) - expect(messages[5].type).toEqual(parser.yy.LINETYPE.DOTTED_OPEN) - expect(messages[6].type).toEqual(parser.yy.LINETYPE.RECT_END) - }) - it('it should handle opt statements', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].type).toEqual(parser.yy.LINETYPE.RECT_START); + expect(messages[1].message).toBe('rgb(200, 255, 200)'); + expect(messages[2].type).toEqual(parser.yy.LINETYPE.RECT_START); + expect(messages[2].message).toBe('rgb(0, 0, 0)'); + expect(messages[3].type).toEqual(parser.yy.LINETYPE.NOTE); + expect(messages[4].type).toEqual(parser.yy.LINETYPE.RECT_END); + expect(messages[5].type).toEqual(parser.yy.LINETYPE.DOTTED_OPEN); + expect(messages[6].type).toEqual(parser.yy.LINETYPE.RECT_END); + }); + it('it should handle opt statements', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + 'opt Perhaps a happy response\n\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) - const actors = parser.yy.getActors() - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + parser.parse(str); + const actors = parser.yy.getActors(); + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(5) - expect(messages[0].from).toBe('Alice') - expect(messages[1].from).toBe('Bob') - }) - it('it should handle alt statements', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(5); + expect(messages[0].from).toBe('Alice'); + expect(messages[1].from).toBe('Bob'); + }); + it('it should handle alt statements', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + @@ -449,22 +461,23 @@ describe('when parsing a sequenceDiagram', function () { 'Bob-->Alice: I am good thanks!\n' + 'else isSick\n' + 'Bob-->Alice: Feel sick...\n' + - 'end' + 'end'; - parser.parse(str) - const actors = parser.yy.getActors() + parser.parse(str); + const actors = parser.yy.getActors(); - expect(actors.Alice.description).toBe('Alice') - actors.Bob.description = 'Bob' + expect(actors.Alice.description).toBe('Alice'); + actors.Bob.description = 'Bob'; - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(7) - expect(messages[0].from).toBe('Alice') - expect(messages[1].from).toBe('Bob') - }) - it('it should handle alt statements with multiple elses', function () { - const str = 'sequenceDiagram\n' + + expect(messages.length).toBe(7); + expect(messages[0].from).toBe('Alice'); + expect(messages[1].from).toBe('Bob'); + }); + it('it should handle alt statements with multiple elses', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + @@ -474,21 +487,22 @@ describe('when parsing a sequenceDiagram', function () { 'Bob-->Alice: Feel sick...\n' + 'else default\n' + 'Bob-->Alice: :-)\n' + - 'end' - parser.parse(str) - const messages = parser.yy.getMessages() - expect(messages.length).toBe(9) - expect(messages[1].from).toBe('Bob') - expect(messages[2].type).toBe(parser.yy.LINETYPE.ALT_START) - expect(messages[3].from).toBe('Bob') - expect(messages[4].type).toBe(parser.yy.LINETYPE.ALT_ELSE) - expect(messages[5].from).toBe('Bob') - expect(messages[6].type).toBe(parser.yy.LINETYPE.ALT_ELSE) - expect(messages[7].from).toBe('Bob') - expect(messages[8].type).toBe(parser.yy.LINETYPE.ALT_END) - }) - it('it should handle par statements a sequenceDiagram', function () { - const str = 'sequenceDiagram\n' + + 'end'; + parser.parse(str); + const messages = parser.yy.getMessages(); + expect(messages.length).toBe(9); + expect(messages[1].from).toBe('Bob'); + expect(messages[2].type).toBe(parser.yy.LINETYPE.ALT_START); + expect(messages[3].from).toBe('Bob'); + expect(messages[4].type).toBe(parser.yy.LINETYPE.ALT_ELSE); + expect(messages[5].from).toBe('Bob'); + expect(messages[6].type).toBe(parser.yy.LINETYPE.ALT_ELSE); + expect(messages[7].from).toBe('Bob'); + expect(messages[8].type).toBe(parser.yy.LINETYPE.ALT_END); + }); + it('it should handle par statements a sequenceDiagram', function() { + const str = + 'sequenceDiagram\n' + 'par Parallel one\n' + 'Alice->>Bob: Hello Bob, how are you?\n' + 'Bob-->>Alice: I am good thanks!\n' + @@ -497,162 +511,170 @@ describe('when parsing a sequenceDiagram', function () { 'Bob-->>Alice: Fine!\n' + 'and Parallel three\n' + 'Alice->>Bob: What do you think about it?\n' + - 'Bob-->>Alice: It\'s good!\n' + - 'end' + "Bob-->>Alice: It's good!\n" + + 'end'; - parser.parse(str) - const actors = parser.yy.getActors() + parser.parse(str); + const actors = parser.yy.getActors(); - expect(actors.Alice.description).toBe('Alice') - expect(actors.Bob.description).toBe('Bob') + expect(actors.Alice.description).toBe('Alice'); + expect(actors.Bob.description).toBe('Bob'); - const messages = parser.yy.getMessages() + const messages = parser.yy.getMessages(); - expect(messages.length).toBe(10) - expect(messages[0].message).toBe('Parallel one') - expect(messages[1].from).toBe('Alice') - expect(messages[2].from).toBe('Bob') - }) - it('it should handle special characters in signals', function () { - const str = 'sequenceDiagram\n' + - 'Alice->Bob: -:<>,;# comment' + expect(messages.length).toBe(10); + expect(messages[0].message).toBe('Parallel one'); + expect(messages[1].from).toBe('Alice'); + expect(messages[2].from).toBe('Bob'); + }); + it('it should handle special characters in signals', function() { + const str = 'sequenceDiagram\n' + 'Alice->Bob: -:<>,;# comment'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[0].message).toBe('-:<>,') - }) - it('it should handle special characters in notes', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[0].message).toBe('-:<>,'); + }); + it('it should handle special characters in notes', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + - 'Note right of Bob: -:<>,;# comment' + 'Note right of Bob: -:<>,;# comment'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].message).toBe('-:<>,') - }) - it('it should handle special characters in loop', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].message).toBe('-:<>,'); + }); + it('it should handle special characters in loop', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'loop -:<>,;# comment\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].message).toBe('-:<>,') - }) - it('it should handle special characters in opt', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].message).toBe('-:<>,'); + }); + it('it should handle special characters in opt', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'opt -:<>,;# comment\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].message).toBe('-:<>,') - }) - it('it should handle special characters in alt', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].message).toBe('-:<>,'); + }); + it('it should handle special characters in alt', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'alt -:<>,;# comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'else ,<>:-#; comment\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].message).toBe('-:<>,') - expect(messages[3].message).toBe(',<>:-') - }) - it('it should handle special characters in par', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].message).toBe('-:<>,'); + expect(messages[3].message).toBe(',<>:-'); + }); + it('it should handle special characters in par', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'par -:<>,;# comment\n' + 'Bob-->Alice: I am good thanks!\n' + 'and ,<>:-#; comment\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].message).toBe('-:<>,') - expect(messages[3].message).toBe(',<>:-') - }) - it('it should handle no-label loop', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].message).toBe('-:<>,'); + expect(messages[3].message).toBe(',<>:-'); + }); + it('it should handle no-label loop', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'loop\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].message).toBe('') - expect(messages[2].message).toBe('I am good thanks!') - }) - it('it should handle no-label opt', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].message).toBe(''); + expect(messages[2].message).toBe('I am good thanks!'); + }); + it('it should handle no-label opt', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'opt # comment\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].message).toBe('') - expect(messages[2].message).toBe('I am good thanks!') - }) - it('it should handle no-label alt', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].message).toBe(''); + expect(messages[2].message).toBe('I am good thanks!'); + }); + it('it should handle no-label alt', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'alt;' + 'Bob-->Alice: I am good thanks!\n' + 'else # comment\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].message).toBe('') - expect(messages[2].message).toBe('I am good thanks!') - expect(messages[3].message).toBe('') - expect(messages[4].message).toBe('I am good thanks!') - }) - it('it should handle no-label par', function () { - const str = 'sequenceDiagram\n' + + const messages = parser.yy.getMessages(); + expect(messages[1].message).toBe(''); + expect(messages[2].message).toBe('I am good thanks!'); + expect(messages[3].message).toBe(''); + expect(messages[4].message).toBe('I am good thanks!'); + }); + it('it should handle no-label par', function() { + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'par;' + 'Bob-->Alice: I am good thanks!\n' + 'and # comment\n' + 'Bob-->Alice: I am good thanks!\n' + - 'end' + 'end'; - parser.parse(str) + parser.parse(str); - const messages = parser.yy.getMessages() - expect(messages[1].message).toBe('') - expect(messages[2].message).toBe('I am good thanks!') - expect(messages[3].message).toBe('') - expect(messages[4].message).toBe('I am good thanks!') - }) -}) + const messages = parser.yy.getMessages(); + expect(messages[1].message).toBe(''); + expect(messages[2].message).toBe('I am good thanks!'); + expect(messages[3].message).toBe(''); + expect(messages[4].message).toBe('I am good thanks!'); + }); +}); -describe('when checking the bounds in a sequenceDiagram', function () { - let conf - beforeEach(function () { - parser.yy = sequenceDb - parser.yy.clear() +describe('when checking the bounds in a sequenceDiagram', function() { + let conf; + beforeEach(function() { + parser.yy = sequenceDb; + parser.yy.clear(); conf = { diagramMarginX: 50, diagramMarginY: 10, @@ -664,131 +686,131 @@ describe('when checking the bounds in a sequenceDiagram', function () { messageMargin: 40, boxTextMargin: 15, noteMargin: 25 - } - renderer.setConf(conf) - }) - it('it should handle a simple bound call', function () { - renderer.bounds.init() + }; + renderer.setConf(conf); + }); + it('it should handle a simple bound call', function() { + renderer.bounds.init(); - renderer.bounds.insert(100, 100, 200, 200) + renderer.bounds.insert(100, 100, 200, 200); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(100) - expect(bounds.starty).toBe(100) - expect(bounds.stopx).toBe(200) - expect(bounds.stopy).toBe(200) - }) - it('it should handle an expanding bound', function () { - renderer.bounds.init() + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(100); + expect(bounds.starty).toBe(100); + expect(bounds.stopx).toBe(200); + expect(bounds.stopy).toBe(200); + }); + it('it should handle an expanding bound', function() { + renderer.bounds.init(); - renderer.bounds.insert(100, 100, 200, 200) - renderer.bounds.insert(25, 50, 300, 400) + renderer.bounds.insert(100, 100, 200, 200); + renderer.bounds.insert(25, 50, 300, 400); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(25) - expect(bounds.starty).toBe(50) - expect(bounds.stopx).toBe(300) - expect(bounds.stopy).toBe(400) - }) - it('it should handle inserts within the bound without changing the outer bounds', function () { - renderer.bounds.init() + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(25); + expect(bounds.starty).toBe(50); + expect(bounds.stopx).toBe(300); + expect(bounds.stopy).toBe(400); + }); + it('it should handle inserts within the bound without changing the outer bounds', function() { + renderer.bounds.init(); - renderer.bounds.insert(100, 100, 200, 200) - renderer.bounds.insert(25, 50, 300, 400) - renderer.bounds.insert(125, 150, 150, 200) + renderer.bounds.insert(100, 100, 200, 200); + renderer.bounds.insert(25, 50, 300, 400); + renderer.bounds.insert(125, 150, 150, 200); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(25) - expect(bounds.starty).toBe(50) - expect(bounds.stopx).toBe(300) - expect(bounds.stopy).toBe(400) - }) - it('it should handle a loop without expanding the area', function () { - renderer.bounds.init() + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(25); + expect(bounds.starty).toBe(50); + expect(bounds.stopx).toBe(300); + expect(bounds.stopy).toBe(400); + }); + it('it should handle a loop without expanding the area', function() { + renderer.bounds.init(); - renderer.bounds.insert(25, 50, 300, 400) - renderer.bounds.verticalPos = 150 - renderer.bounds.newLoop() - renderer.bounds.insert(125, 150, 150, 200) + renderer.bounds.insert(25, 50, 300, 400); + renderer.bounds.verticalPos = 150; + renderer.bounds.newLoop(); + renderer.bounds.insert(125, 150, 150, 200); - const loop = renderer.bounds.endLoop() + const loop = renderer.bounds.endLoop(); - expect(loop.startx).toBe(125 - conf.boxMargin) - expect(loop.starty).toBe(150 - conf.boxMargin) - expect(loop.stopx).toBe(150 + conf.boxMargin) - expect(loop.stopy).toBe(200 + conf.boxMargin) + expect(loop.startx).toBe(125 - conf.boxMargin); + expect(loop.starty).toBe(150 - conf.boxMargin); + expect(loop.stopx).toBe(150 + conf.boxMargin); + expect(loop.stopy).toBe(200 + conf.boxMargin); // Check bounds of first loop - const bounds = renderer.bounds.getBounds() + const bounds = renderer.bounds.getBounds(); - expect(bounds.startx).toBe(25) - expect(bounds.starty).toBe(50) - expect(bounds.stopx).toBe(300) - expect(bounds.stopy).toBe(400) - }) - it('it should handle multiple loops withtout expanding the bounds', function () { - renderer.bounds.init() + expect(bounds.startx).toBe(25); + expect(bounds.starty).toBe(50); + expect(bounds.stopx).toBe(300); + expect(bounds.stopy).toBe(400); + }); + it('it should handle multiple loops withtout expanding the bounds', function() { + renderer.bounds.init(); - renderer.bounds.insert(100, 100, 1000, 1000) - renderer.bounds.verticalPos = 200 - renderer.bounds.newLoop() - renderer.bounds.newLoop() - renderer.bounds.insert(200, 200, 300, 300) + renderer.bounds.insert(100, 100, 1000, 1000); + renderer.bounds.verticalPos = 200; + renderer.bounds.newLoop(); + renderer.bounds.newLoop(); + renderer.bounds.insert(200, 200, 300, 300); // Check bounds of first loop - let loop = renderer.bounds.endLoop() + let loop = renderer.bounds.endLoop(); - expect(loop.startx).toBe(200 - conf.boxMargin) - expect(loop.starty).toBe(200 - conf.boxMargin) - expect(loop.stopx).toBe(300 + conf.boxMargin) - expect(loop.stopy).toBe(300 + conf.boxMargin) + expect(loop.startx).toBe(200 - conf.boxMargin); + expect(loop.starty).toBe(200 - conf.boxMargin); + expect(loop.stopx).toBe(300 + conf.boxMargin); + expect(loop.stopy).toBe(300 + conf.boxMargin); // Check bounds of second loop - loop = renderer.bounds.endLoop() + loop = renderer.bounds.endLoop(); - expect(loop.startx).toBe(200 - 2 * conf.boxMargin) - expect(loop.starty).toBe(200 - 2 * conf.boxMargin) - expect(loop.stopx).toBe(300 + 2 * conf.boxMargin) - expect(loop.stopy).toBe(300 + 2 * conf.boxMargin) + expect(loop.startx).toBe(200 - 2 * conf.boxMargin); + expect(loop.starty).toBe(200 - 2 * conf.boxMargin); + expect(loop.stopx).toBe(300 + 2 * conf.boxMargin); + expect(loop.stopy).toBe(300 + 2 * conf.boxMargin); // Check bounds of first loop - const bounds = renderer.bounds.getBounds() + const bounds = renderer.bounds.getBounds(); - expect(bounds.startx).toBe(100) - expect(bounds.starty).toBe(100) - expect(bounds.stopx).toBe(1000) - expect(bounds.stopy).toBe(1000) - }) - it('it should handle a loop that expands the area', function () { - renderer.bounds.init() + expect(bounds.startx).toBe(100); + expect(bounds.starty).toBe(100); + expect(bounds.stopx).toBe(1000); + expect(bounds.stopy).toBe(1000); + }); + it('it should handle a loop that expands the area', function() { + renderer.bounds.init(); - renderer.bounds.insert(100, 100, 200, 200) - renderer.bounds.verticalPos = 200 - renderer.bounds.newLoop() - renderer.bounds.insert(50, 50, 300, 300) + renderer.bounds.insert(100, 100, 200, 200); + renderer.bounds.verticalPos = 200; + renderer.bounds.newLoop(); + renderer.bounds.insert(50, 50, 300, 300); - const loop = renderer.bounds.endLoop() + const loop = renderer.bounds.endLoop(); - expect(loop.startx).toBe(50 - conf.boxMargin) - expect(loop.starty).toBe(50 - conf.boxMargin) - expect(loop.stopx).toBe(300 + conf.boxMargin) - expect(loop.stopy).toBe(300 + conf.boxMargin) + expect(loop.startx).toBe(50 - conf.boxMargin); + expect(loop.starty).toBe(50 - conf.boxMargin); + expect(loop.stopx).toBe(300 + conf.boxMargin); + expect(loop.stopy).toBe(300 + conf.boxMargin); // Check bounds after the loop - const bounds = renderer.bounds.getBounds() + const bounds = renderer.bounds.getBounds(); - expect(bounds.startx).toBe(loop.startx) - expect(bounds.starty).toBe(loop.starty) - expect(bounds.stopx).toBe(loop.stopx) - expect(bounds.stopy).toBe(loop.stopy) - }) -}) + expect(bounds.startx).toBe(loop.startx); + expect(bounds.starty).toBe(loop.starty); + expect(bounds.stopx).toBe(loop.stopx); + expect(bounds.stopy).toBe(loop.stopy); + }); +}); -describe('when rendering a sequenceDiagram', function () { - let conf - beforeEach(function () { - parser.yy = sequenceDb - parser.yy.clear() +describe('when rendering a sequenceDiagram', function() { + let conf; + beforeEach(function() { + parser.yy = sequenceDb; + parser.yy.clear(); conf = { diagramMarginX: 50, @@ -801,210 +823,213 @@ describe('when rendering a sequenceDiagram', function () { messageMargin: 40, boxTextMargin: 15, noteMargin: 25 - } - renderer.setConf(conf) + }; + renderer.setConf(conf); }); - ['tspan', 'fo', 'old', undefined].forEach(function (textPlacement) { - it('it should handle one actor, when textPlacement is ' + textPlacement, function () { - renderer.setConf(addConf(conf, 'textPlacement', textPlacement)) - renderer.bounds.init() - const str = 'sequenceDiagram\n' + - 'participant Alice' + ['tspan', 'fo', 'old', undefined].forEach(function(textPlacement) { + it('it should handle one actor, when textPlacement is ' + textPlacement, function() { + renderer.setConf(addConf(conf, 'textPlacement', textPlacement)); + renderer.bounds.init(); + const str = 'sequenceDiagram\n' + 'participant Alice'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) - expect(bounds.stopx).toBe(conf.width) - expect(bounds.stopy).toBe(conf.height) - }) - }) - it('it should handle same actor with different whitespace properly', function () { - renderer.bounds.init() + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); + expect(bounds.stopx).toBe(conf.width); + expect(bounds.stopy).toBe(conf.height); + }); + }); + it('it should handle same actor with different whitespace properly', function() { + renderer.bounds.init(); - const str = 'sequenceDiagram\n' + + const str = + 'sequenceDiagram\n' + 'participant Alice\n' + 'participant Alice \n' + - 'participant Alice \n' + 'participant Alice \n'; - parser.parse(str) + parser.parse(str); - const actors = parser.yy.getActors() - expect(Object.keys(actors)).toEqual(['Alice']) - }) - it('it should handle one actor and a centered note', function () { - renderer.bounds.init() - const str = 'sequenceDiagram\n' + - 'participant Alice\n' + - 'Note over Alice: Alice thinks\n' + const actors = parser.yy.getActors(); + expect(Object.keys(actors)).toEqual(['Alice']); + }); + it('it should handle one actor and a centered note', function() { + renderer.bounds.init(); + const str = 'sequenceDiagram\n' + 'participant Alice\n' + 'Note over Alice: Alice thinks\n'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) - expect(bounds.stopx).toBe(conf.width) + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); + expect(bounds.stopx).toBe(conf.width); // 10 comes from mock of text height - expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10) - }) - it('it should handle one actor and a note to the left', function () { - renderer.bounds.init() - const str = 'sequenceDiagram\n' + - 'participant Alice\n' + - 'Note left of Alice: Alice thinks' + expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10); + }); + it('it should handle one actor and a note to the left', function() { + renderer.bounds.init(); + const str = 'sequenceDiagram\n' + 'participant Alice\n' + 'Note left of Alice: Alice thinks'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(-(conf.width / 2) - (conf.actorMargin / 2)) - expect(bounds.starty).toBe(0) - expect(bounds.stopx).toBe(conf.width) + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2); + expect(bounds.starty).toBe(0); + expect(bounds.stopx).toBe(conf.width); // 10 comes from mock of text height - expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10) - }) - it('it should handle one actor and a note to the right', function () { - renderer.bounds.init() - const str = 'sequenceDiagram\n' + - 'participant Alice\n' + - 'Note right of Alice: Alice thinks' + expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10); + }); + it('it should handle one actor and a note to the right', function() { + renderer.bounds.init(); + const str = 'sequenceDiagram\n' + 'participant Alice\n' + 'Note right of Alice: Alice thinks'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) - expect(bounds.stopx).toBe((conf.width / 2) + (conf.actorMargin / 2) + conf.width) + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); + expect(bounds.stopx).toBe(conf.width / 2 + conf.actorMargin / 2 + conf.width); // 10 comes from mock of text height - expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10) - }) - it('it should handle two actors', function () { - renderer.bounds.init() - const str = 'sequenceDiagram\n' + - 'Alice->Bob: Hello Bob, how are you?' + expect(bounds.stopy).toBe(conf.height + conf.boxMargin + 2 * conf.noteMargin + 10); + }); + it('it should handle two actors', function() { + renderer.bounds.init(); + const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) - expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin) - expect(bounds.stopy).toBe(0 + conf.messageMargin + conf.height) - }) - it('it should handle two actors and two centered shared notes', function () { - renderer.bounds.init() - const str = 'sequenceDiagram\n' + + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); + expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); + expect(bounds.stopy).toBe(0 + conf.messageMargin + conf.height); + }); + it('it should handle two actors and two centered shared notes', function() { + renderer.bounds.init(); + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note over Alice,Bob: Looks\n' + - 'Note over Bob,Alice: Looks back\n' + 'Note over Bob,Alice: Looks back\n'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) - expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin) - expect(bounds.stopy).toBe(conf.height + conf.messageMargin + 2 * (conf.boxMargin + 2 * conf.noteMargin + 10)) - }) - it('it should draw two actors and two messages', function () { - renderer.bounds.init() - const str = 'sequenceDiagram\n' + - 'Alice->Bob: Hello Bob, how are you?\n' + - 'Bob->Alice: Fine!' + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); + expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); + expect(bounds.stopy).toBe( + conf.height + conf.messageMargin + 2 * (conf.boxMargin + 2 * conf.noteMargin + 10) + ); + }); + it('it should draw two actors and two messages', function() { + renderer.bounds.init(); + const str = 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Bob->Alice: Fine!'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) - expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin) - expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height) - }) - it('it should draw two actors notes to the right', function () { - renderer.bounds.init() - const str = 'sequenceDiagram\n' + + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); + expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin); + expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height); + }); + it('it should draw two actors notes to the right', function() { + renderer.bounds.init(); + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note right of Bob: Bob thinks\n' + - 'Bob->Alice: Fine!' + 'Bob->Alice: Fine!'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); - const expStopX = conf.actorMargin + conf.width + (conf.width / 2) + conf.noteMargin + conf.width + const expStopX = conf.actorMargin + conf.width + conf.width / 2 + conf.noteMargin + conf.width; - expect(bounds.stopx).toBe(expStopX) - expect(bounds.stopy).toBe(2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin) - }) - it('it should draw two actors notes to the left', function () { - renderer.bounds.init() - const str = 'sequenceDiagram\n' + + expect(bounds.stopx).toBe(expStopX); + expect(bounds.stopy).toBe( + 2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin + ); + }); + it('it should draw two actors notes to the left', function() { + renderer.bounds.init(); + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'Note left of Alice: Bob thinks\n' + - 'Bob->Alice: Fine!' + 'Bob->Alice: Fine!'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(-(conf.width / 2) - (conf.actorMargin / 2)) - expect(bounds.starty).toBe(0) + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(-(conf.width / 2) - conf.actorMargin / 2); + expect(bounds.starty).toBe(0); - expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin) - expect(bounds.stopy).toBe(2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin) - }) - it('it should draw two loops', function () { - renderer.bounds.init() - const str = 'sequenceDiagram\n' + + expect(bounds.stopx).toBe(conf.width * 2 + conf.actorMargin); + expect(bounds.stopy).toBe( + 2 * conf.messageMargin + conf.height + conf.boxMargin + 10 + 2 * conf.noteMargin + ); + }); + it('it should draw two loops', function() { + renderer.bounds.init(); + const str = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n' + 'loop Cheers\n' + 'Bob->Alice: Fine!\n' + - 'end' - parser.parse(str) - renderer.draw(str, 'tst') + 'end'; + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); - expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin) - expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height + 3 * conf.boxMargin + conf.boxTextMargin) - }) - it('it should draw background rect', function () { - renderer.bounds.init() + expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin); + expect(bounds.stopy).toBe( + 0 + 2 * conf.messageMargin + conf.height + 3 * conf.boxMargin + conf.boxTextMargin + ); + }); + it('it should draw background rect', function() { + renderer.bounds.init(); const str = ` sequenceDiagram Alice->Bob: Hello Bob, are you alright? rect rgb(0, 0, 0) Bob->Alice: I feel surrounded by darkness end - ` - parser.parse(str) - renderer.draw(str, 'tst') - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) + `; + parser.parse(str); + renderer.draw(str, 'tst'); + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); - expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin) - expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height + 3 * conf.boxMargin) - }) -}) + expect(bounds.stopx).toBe(0 + conf.width * 2 + conf.actorMargin); + expect(bounds.stopy).toBe(0 + 2 * conf.messageMargin + conf.height + 3 * conf.boxMargin); + }); +}); -describe('when rendering a sequenceDiagram with actor mirror activated', function () { - let conf - beforeEach(function () { - parser.yy = sequenceDb - parser.yy.clear() +describe('when rendering a sequenceDiagram with actor mirror activated', function() { + let conf; + beforeEach(function() { + parser.yy = sequenceDb; + parser.yy.clear(); conf = { diagramMarginX: 50, @@ -1021,24 +1046,23 @@ describe('when rendering a sequenceDiagram with actor mirror activated', functio // Depending on css styling this might need adjustment // Prolongs the edge of the diagram downwards bottomMarginAdj: 1 - } - renderer.setConf(conf) + }; + renderer.setConf(conf); }); - ['tspan', 'fo', 'old', undefined].forEach(function (textPlacement) { - it('it should handle one actor, when textPlacement is' + textPlacement, function () { - renderer.setConf(addConf(conf, 'textPlacement', textPlacement)) - renderer.bounds.init() - const str = 'sequenceDiagram\n' + - 'participant Alice' + ['tspan', 'fo', 'old', undefined].forEach(function(textPlacement) { + it('it should handle one actor, when textPlacement is' + textPlacement, function() { + renderer.setConf(addConf(conf, 'textPlacement', textPlacement)); + renderer.bounds.init(); + const str = 'sequenceDiagram\n' + 'participant Alice'; - parser.parse(str) - renderer.draw(str, 'tst') + parser.parse(str); + renderer.draw(str, 'tst'); - const bounds = renderer.bounds.getBounds() - expect(bounds.startx).toBe(0) - expect(bounds.starty).toBe(0) - expect(bounds.stopx).toBe(conf.width) - expect(bounds.stopy).toBe(2 * conf.height + 2 * conf.boxMargin) - }) - }) -}) + const bounds = renderer.bounds.getBounds(); + expect(bounds.startx).toBe(0); + expect(bounds.starty).toBe(0); + expect(bounds.stopx).toBe(conf.width); + expect(bounds.stopy).toBe(2 * conf.height + 2 * conf.boxMargin); + }); + }); +}); diff --git a/src/diagrams/sequence/sequenceRenderer.js b/src/diagrams/sequence/sequenceRenderer.js index 4e4b0f74d..6ebd5a52d 100644 --- a/src/diagrams/sequence/sequenceRenderer.js +++ b/src/diagrams/sequence/sequenceRenderer.js @@ -1,14 +1,13 @@ -import * as d3 from 'd3' +import * as d3 from 'd3'; -import svgDraw from './svgDraw' -import { logger } from '../../logger' -import { parser } from './parser/sequenceDiagram' -import sequenceDb from './sequenceDb' +import svgDraw from './svgDraw'; +import { logger } from '../../logger'; +import { parser } from './parser/sequenceDiagram'; +import sequenceDb from './sequenceDb'; -parser.yy = sequenceDb +parser.yy = sequenceDb; const conf = { - diagramMarginX: 50, diagramMarginY: 30, // Margin between actors @@ -38,7 +37,7 @@ const conf = { textPlacement: 'tspan', showSequenceNumbers: false -} +}; export const bounds = { data: { @@ -51,69 +50,69 @@ export const bounds = { sequenceItems: [], activations: [], - init: function () { - this.sequenceItems = [] - this.activations = [] + init: function() { + this.sequenceItems = []; + this.activations = []; this.data = { startx: undefined, stopx: undefined, starty: undefined, stopy: undefined - } - this.verticalPos = 0 + }; + this.verticalPos = 0; }, - updateVal: function (obj, key, val, fun) { + updateVal: function(obj, key, val, fun) { if (typeof obj[key] === 'undefined') { - obj[key] = val + obj[key] = val; } else { - obj[key] = fun(val, obj[key]) + obj[key] = fun(val, obj[key]); } }, - updateBounds: function (startx, starty, stopx, stopy) { - const _self = this - let cnt = 0 - function updateFn (type) { - return function updateItemBounds (item) { - cnt++ + updateBounds: function(startx, starty, stopx, stopy) { + const _self = this; + let cnt = 0; + function updateFn(type) { + return function updateItemBounds(item) { + cnt++; // The loop sequenceItems is a stack so the biggest margins in the beginning of the sequenceItems - const n = _self.sequenceItems.length - cnt + 1 + const n = _self.sequenceItems.length - cnt + 1; - _self.updateVal(item, 'starty', starty - n * conf.boxMargin, Math.min) - _self.updateVal(item, 'stopy', stopy + n * conf.boxMargin, Math.max) + _self.updateVal(item, 'starty', starty - n * conf.boxMargin, Math.min); + _self.updateVal(item, 'stopy', stopy + n * conf.boxMargin, Math.max); - _self.updateVal(bounds.data, 'startx', startx - n * conf.boxMargin, Math.min) - _self.updateVal(bounds.data, 'stopx', stopx + n * conf.boxMargin, Math.max) + _self.updateVal(bounds.data, 'startx', startx - n * conf.boxMargin, Math.min); + _self.updateVal(bounds.data, 'stopx', stopx + n * conf.boxMargin, Math.max); if (!(type === 'activation')) { - _self.updateVal(item, 'startx', startx - n * conf.boxMargin, Math.min) - _self.updateVal(item, 'stopx', stopx + n * conf.boxMargin, Math.max) + _self.updateVal(item, 'startx', startx - n * conf.boxMargin, Math.min); + _self.updateVal(item, 'stopx', stopx + n * conf.boxMargin, Math.max); - _self.updateVal(bounds.data, 'starty', starty - n * conf.boxMargin, Math.min) - _self.updateVal(bounds.data, 'stopy', stopy + n * conf.boxMargin, Math.max) + _self.updateVal(bounds.data, 'starty', starty - n * conf.boxMargin, Math.min); + _self.updateVal(bounds.data, 'stopy', stopy + n * conf.boxMargin, Math.max); } - } + }; } - this.sequenceItems.forEach(updateFn()) - this.activations.forEach(updateFn('activation')) + this.sequenceItems.forEach(updateFn()); + this.activations.forEach(updateFn('activation')); }, - insert: function (startx, starty, stopx, stopy) { - const _startx = Math.min(startx, stopx) - const _stopx = Math.max(startx, stopx) - const _starty = Math.min(starty, stopy) - const _stopy = Math.max(starty, stopy) + insert: function(startx, starty, stopx, stopy) { + const _startx = Math.min(startx, stopx); + const _stopx = Math.max(startx, stopx); + const _starty = Math.min(starty, stopy); + const _stopy = Math.max(starty, stopy); - this.updateVal(bounds.data, 'startx', _startx, Math.min) - this.updateVal(bounds.data, 'starty', _starty, Math.min) - this.updateVal(bounds.data, 'stopx', _stopx, Math.max) - this.updateVal(bounds.data, 'stopy', _stopy, Math.max) + this.updateVal(bounds.data, 'startx', _startx, Math.min); + this.updateVal(bounds.data, 'starty', _starty, Math.min); + this.updateVal(bounds.data, 'stopx', _stopx, Math.max); + this.updateVal(bounds.data, 'stopy', _stopy, Math.max); - this.updateBounds(_startx, _starty, _stopx, _stopy) + this.updateBounds(_startx, _starty, _stopx, _stopy); }, - newActivation: function (message, diagram) { - const actorRect = parser.yy.getActors()[message.from.actor] - const stackedSize = actorActivations(message.from.actor).length - const x = actorRect.x + conf.width / 2 + (stackedSize - 1) * conf.activationWidth / 2 + newActivation: function(message, diagram) { + const actorRect = parser.yy.getActors()[message.from.actor]; + const stackedSize = actorActivations(message.from.actor).length; + const x = actorRect.x + conf.width / 2 + ((stackedSize - 1) * conf.activationWidth) / 2; this.activations.push({ startx: x, starty: this.verticalPos + 2, @@ -121,59 +120,68 @@ export const bounds = { stopy: undefined, actor: message.from.actor, anchored: svgDraw.anchorElement(diagram) - }) + }); }, - endActivation: function (message) { + endActivation: function(message) { // find most recent activation for given actor const lastActorActivationIdx = this.activations - .map(function (activation) { return activation.actor }) - .lastIndexOf(message.from.actor) - const activation = this.activations.splice(lastActorActivationIdx, 1)[0] - return activation + .map(function(activation) { + return activation.actor; + }) + .lastIndexOf(message.from.actor); + const activation = this.activations.splice(lastActorActivationIdx, 1)[0]; + return activation; }, - newLoop: function (title, fill) { - this.sequenceItems.push({ startx: undefined, starty: this.verticalPos, stopx: undefined, stopy: undefined, title: title, fill: fill }) + newLoop: function(title, fill) { + this.sequenceItems.push({ + startx: undefined, + starty: this.verticalPos, + stopx: undefined, + stopy: undefined, + title: title, + fill: fill + }); }, - endLoop: function () { - const loop = this.sequenceItems.pop() - return loop + endLoop: function() { + const loop = this.sequenceItems.pop(); + return loop; }, - addSectionToLoop: function (message) { - const loop = this.sequenceItems.pop() - loop.sections = loop.sections || [] - loop.sectionTitles = loop.sectionTitles || [] - loop.sections.push(bounds.getVerticalPos()) - loop.sectionTitles.push(message) - this.sequenceItems.push(loop) + addSectionToLoop: function(message) { + const loop = this.sequenceItems.pop(); + loop.sections = loop.sections || []; + loop.sectionTitles = loop.sectionTitles || []; + loop.sections.push(bounds.getVerticalPos()); + loop.sectionTitles.push(message); + this.sequenceItems.push(loop); }, - bumpVerticalPos: function (bump) { - this.verticalPos = this.verticalPos + bump - this.data.stopy = this.verticalPos + bumpVerticalPos: function(bump) { + this.verticalPos = this.verticalPos + bump; + this.data.stopy = this.verticalPos; }, - getVerticalPos: function () { - return this.verticalPos + getVerticalPos: function() { + return this.verticalPos; }, - getBounds: function () { - return this.data + getBounds: function() { + return this.data; } -} +}; const _drawLongText = (text, x, y, g, width) => { - let textHeight = 0 - const lines = text.split(//ig) + let textHeight = 0; + const lines = text.split(//gi); for (const line of lines) { - const textObj = svgDraw.getTextObj() - textObj.x = x - textObj.y = y + textHeight - textObj.textMargin = conf.noteMargin - textObj.dy = '1em' - textObj.text = line - textObj.class = 'noteText' - const textElem = svgDraw.drawText(g, textObj, width) - textHeight += (textElem._groups || textElem)[0][0].getBBox().height + const textObj = svgDraw.getTextObj(); + textObj.x = x; + textObj.y = y + textHeight; + textObj.textMargin = conf.noteMargin; + textObj.dy = '1em'; + textObj.text = line; + textObj.class = 'noteText'; + const textElem = svgDraw.drawText(g, textObj, width); + textHeight += (textElem._groups || textElem)[0][0].getBBox().height; } - return textHeight -} + return textHeight; +}; /** * Draws an actor in the diagram with the attaced line @@ -181,22 +189,33 @@ const _drawLongText = (text, x, y, g, width) => { * @param pos The position if the actor in the liost of actors * @param description The text in the box */ -const drawNote = function (elem, startx, verticalPos, msg, forceWidth) { - const rect = svgDraw.getNoteRect() - rect.x = startx - rect.y = verticalPos - rect.width = forceWidth || conf.width - rect.class = 'note' +const drawNote = function(elem, startx, verticalPos, msg, forceWidth) { + const rect = svgDraw.getNoteRect(); + rect.x = startx; + rect.y = verticalPos; + rect.width = forceWidth || conf.width; + rect.class = 'note'; - let g = elem.append('g') - const rectElem = svgDraw.drawRect(g, rect) + let g = elem.append('g'); + const rectElem = svgDraw.drawRect(g, rect); - const textHeight = _drawLongText(msg.message, startx - 4, verticalPos + 24, g, rect.width - conf.noteMargin) + const textHeight = _drawLongText( + msg.message, + startx - 4, + verticalPos + 24, + g, + rect.width - conf.noteMargin + ); - bounds.insert(startx, verticalPos, startx + rect.width, verticalPos + 2 * conf.noteMargin + textHeight) - rectElem.attr('height', textHeight + 2 * conf.noteMargin) - bounds.bumpVerticalPos(textHeight + 2 * conf.noteMargin) -} + bounds.insert( + startx, + verticalPos, + startx + rect.width, + verticalPos + 2 * conf.noteMargin + textHeight + ); + rectElem.attr('height', textHeight + 2 * conf.noteMargin); + bounds.bumpVerticalPos(textHeight + 2 * conf.noteMargin); +}; /** * Draws a message @@ -207,70 +226,104 @@ const drawNote = function (elem, startx, verticalPos, msg, forceWidth) { * @param txtCenter * @param msg */ -const drawMessage = function (elem, startx, stopx, verticalPos, msg, sequenceIndex) { - const g = elem.append('g') - const txtCenter = startx + (stopx - startx) / 2 +const drawMessage = function(elem, startx, stopx, verticalPos, msg, sequenceIndex) { + const g = elem.append('g'); + const txtCenter = startx + (stopx - startx) / 2; - const textElem = g.append('text') // text label for the x axis + const textElem = g + .append('text') // text label for the x axis .attr('x', txtCenter) .attr('y', verticalPos - 7) .style('text-anchor', 'middle') .attr('class', 'messageText') - .text(msg.message) + .text(msg.message); - let textWidth = (textElem._groups || textElem)[0][0].getBBox().width + let textWidth = (textElem._groups || textElem)[0][0].getBBox().width; - let line + let line; if (startx === stopx) { if (conf.rightAngles) { - line = g.append('path').attr('d', `M ${startx},${verticalPos} H ${startx + (conf.width / 2)} V ${verticalPos + 25} H ${startx}`) + line = g + .append('path') + .attr( + 'd', + `M ${startx},${verticalPos} H ${startx + conf.width / 2} V ${verticalPos + + 25} H ${startx}` + ); } else { - line = g.append('path') - .attr('d', 'M ' + startx + ',' + verticalPos + ' C ' + (startx + 60) + ',' + (verticalPos - 10) + ' ' + (startx + 60) + ',' + - (verticalPos + 30) + ' ' + startx + ',' + (verticalPos + 20)) + line = g + .append('path') + .attr( + 'd', + 'M ' + + startx + + ',' + + verticalPos + + ' C ' + + (startx + 60) + + ',' + + (verticalPos - 10) + + ' ' + + (startx + 60) + + ',' + + (verticalPos + 30) + + ' ' + + startx + + ',' + + (verticalPos + 20) + ); } - bounds.bumpVerticalPos(30) - const dx = Math.max(textWidth / 2, 100) - bounds.insert(startx - dx, bounds.getVerticalPos() - 10, stopx + dx, bounds.getVerticalPos()) + bounds.bumpVerticalPos(30); + const dx = Math.max(textWidth / 2, 100); + bounds.insert(startx - dx, bounds.getVerticalPos() - 10, stopx + dx, bounds.getVerticalPos()); } else { - line = g.append('line') - line.attr('x1', startx) - line.attr('y1', verticalPos) - line.attr('x2', stopx) - line.attr('y2', verticalPos) - bounds.insert(startx, bounds.getVerticalPos() - 10, stopx, bounds.getVerticalPos()) + line = g.append('line'); + line.attr('x1', startx); + line.attr('y1', verticalPos); + line.attr('x2', stopx); + line.attr('y2', verticalPos); + bounds.insert(startx, bounds.getVerticalPos() - 10, stopx, bounds.getVerticalPos()); } // Make an SVG Container // Draw the line - if (msg.type === parser.yy.LINETYPE.DOTTED || msg.type === parser.yy.LINETYPE.DOTTED_CROSS || msg.type === parser.yy.LINETYPE.DOTTED_OPEN) { - line.style('stroke-dasharray', ('3, 3')) - line.attr('class', 'messageLine1') + if ( + msg.type === parser.yy.LINETYPE.DOTTED || + msg.type === parser.yy.LINETYPE.DOTTED_CROSS || + msg.type === parser.yy.LINETYPE.DOTTED_OPEN + ) { + line.style('stroke-dasharray', '3, 3'); + line.attr('class', 'messageLine1'); } else { - line.attr('class', 'messageLine0') + line.attr('class', 'messageLine0'); } - let url = '' + let url = ''; if (conf.arrowMarkerAbsolute) { - url = window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search - url = url.replace(/\(/g, '\\(') - url = url.replace(/\)/g, '\\)') + url = + window.location.protocol + + '//' + + window.location.host + + window.location.pathname + + window.location.search; + url = url.replace(/\(/g, '\\('); + url = url.replace(/\)/g, '\\)'); } - line.attr('stroke-width', 2) - line.attr('stroke', 'black') - line.style('fill', 'none') // remove any fill colour + line.attr('stroke-width', 2); + line.attr('stroke', 'black'); + line.style('fill', 'none'); // remove any fill colour if (msg.type === parser.yy.LINETYPE.SOLID || msg.type === parser.yy.LINETYPE.DOTTED) { - line.attr('marker-end', 'url(' + url + '#arrowhead)') + line.attr('marker-end', 'url(' + url + '#arrowhead)'); } if (msg.type === parser.yy.LINETYPE.SOLID_CROSS || msg.type === parser.yy.LINETYPE.DOTTED_CROSS) { - line.attr('marker-end', 'url(' + url + '#crosshead)') + line.attr('marker-end', 'url(' + url + '#crosshead)'); } // add node number if (conf.showSequenceNumbers) { - line.attr('marker-start', 'url(' + url + '#sequencenumber)') + line.attr('marker-start', 'url(' + url + '#sequencenumber)'); g.append('text') .attr('x', startx) .attr('y', verticalPos + 4) @@ -279,263 +332,306 @@ const drawMessage = function (elem, startx, stopx, verticalPos, msg, sequenceInd .attr('text-anchor', 'middle') .attr('textLength', '16px') .attr('class', 'sequenceNumber') - .text(sequenceIndex) + .text(sequenceIndex); } -} +}; -export const drawActors = function (diagram, actors, actorKeys, verticalPos) { +export const drawActors = function(diagram, actors, actorKeys, verticalPos) { // Draw the actors for (let i = 0; i < actorKeys.length; i++) { - const key = actorKeys[i] + const key = actorKeys[i]; // Add some rendering data to the object - actors[key].x = i * conf.actorMargin + i * conf.width - actors[key].y = verticalPos - actors[key].width = conf.diagramMarginX - actors[key].height = conf.diagramMarginY + actors[key].x = i * conf.actorMargin + i * conf.width; + actors[key].y = verticalPos; + actors[key].width = conf.diagramMarginX; + actors[key].height = conf.diagramMarginY; // Draw the box with the attached line - svgDraw.drawActor(diagram, actors[key].x, verticalPos, actors[key].description, conf) - bounds.insert(actors[key].x, verticalPos, actors[key].x + conf.width, conf.height) + svgDraw.drawActor(diagram, actors[key].x, verticalPos, actors[key].description, conf); + bounds.insert(actors[key].x, verticalPos, actors[key].x + conf.width, conf.height); } // Add a margin between the actor boxes and the first arrow - bounds.bumpVerticalPos(conf.height) -} + bounds.bumpVerticalPos(conf.height); +}; -export const setConf = function (cnf) { - const keys = Object.keys(cnf) +export const setConf = function(cnf) { + const keys = Object.keys(cnf); - keys.forEach(function (key) { - conf[key] = cnf[key] - }) -} + keys.forEach(function(key) { + conf[key] = cnf[key]; + }); +}; -const actorActivations = function (actor) { - return bounds.activations.filter(function (activation) { - return activation.actor === actor - }) -} +const actorActivations = function(actor) { + return bounds.activations.filter(function(activation) { + return activation.actor === actor; + }); +}; -const actorFlowVerticaBounds = function (actor) { +const actorFlowVerticaBounds = function(actor) { // handle multiple stacked activations for same actor - const actors = parser.yy.getActors() - const activations = actorActivations(actor) + const actors = parser.yy.getActors(); + const activations = actorActivations(actor); - const left = activations.reduce(function (acc, activation) { return Math.min(acc, activation.startx) }, actors[actor].x + conf.width / 2) - const right = activations.reduce(function (acc, activation) { return Math.max(acc, activation.stopx) }, actors[actor].x + conf.width / 2) - return [left, right] -} + const left = activations.reduce(function(acc, activation) { + return Math.min(acc, activation.startx); + }, actors[actor].x + conf.width / 2); + const right = activations.reduce(function(acc, activation) { + return Math.max(acc, activation.stopx); + }, actors[actor].x + conf.width / 2); + return [left, right]; +}; /** * Draws a flowchart in the tag with id: id based on the graph definition in text. * @param text * @param id */ -export const draw = function (text, id) { - parser.yy.clear() - parser.parse(text + '\n') +export const draw = function(text, id) { + parser.yy.clear(); + parser.parse(text + '\n'); - bounds.init() - const diagram = d3.select(`[id="${id}"]`) + bounds.init(); + const diagram = d3.select(`[id="${id}"]`); - let startx - let stopx - let forceWidth + let startx; + let stopx; + let forceWidth; // Fetch data from the parsing - const actors = parser.yy.getActors() - const actorKeys = parser.yy.getActorKeys() - const messages = parser.yy.getMessages() - const title = parser.yy.getTitle() - drawActors(diagram, actors, actorKeys, 0) + const actors = parser.yy.getActors(); + const actorKeys = parser.yy.getActorKeys(); + const messages = parser.yy.getMessages(); + const title = parser.yy.getTitle(); + drawActors(diagram, actors, actorKeys, 0); // The arrow head definition is attached to the svg once - svgDraw.insertArrowHead(diagram) - svgDraw.insertArrowCrossHead(diagram) - svgDraw.insertSequenceNumber(diagram) + svgDraw.insertArrowHead(diagram); + svgDraw.insertArrowCrossHead(diagram); + svgDraw.insertSequenceNumber(diagram); - function activeEnd (msg, verticalPos) { - const activationData = bounds.endActivation(msg) + function activeEnd(msg, verticalPos) { + const activationData = bounds.endActivation(msg); if (activationData.starty + 18 > verticalPos) { - activationData.starty = verticalPos - 6 - verticalPos += 12 + activationData.starty = verticalPos - 6; + verticalPos += 12; } - svgDraw.drawActivation(diagram, activationData, verticalPos, conf, actorActivations(msg.from.actor).length) + svgDraw.drawActivation( + diagram, + activationData, + verticalPos, + conf, + actorActivations(msg.from.actor).length + ); - bounds.insert(activationData.startx, verticalPos - 10, activationData.stopx, verticalPos) + bounds.insert(activationData.startx, verticalPos - 10, activationData.stopx, verticalPos); } // const lastMsg // Draw the messages/signals - let sequenceIndex = 1 - messages.forEach(function (msg) { - let loopData + let sequenceIndex = 1; + messages.forEach(function(msg) { + let loopData; switch (msg.type) { case parser.yy.LINETYPE.NOTE: - bounds.bumpVerticalPos(conf.boxMargin) + bounds.bumpVerticalPos(conf.boxMargin); - startx = actors[msg.from].x - stopx = actors[msg.to].x + startx = actors[msg.from].x; + stopx = actors[msg.to].x; if (msg.placement === parser.yy.PLACEMENT.RIGHTOF) { - drawNote(diagram, startx + (conf.width + conf.actorMargin) / 2, bounds.getVerticalPos(), msg) + drawNote( + diagram, + startx + (conf.width + conf.actorMargin) / 2, + bounds.getVerticalPos(), + msg + ); } else if (msg.placement === parser.yy.PLACEMENT.LEFTOF) { - drawNote(diagram, startx - (conf.width + conf.actorMargin) / 2, bounds.getVerticalPos(), msg) + drawNote( + diagram, + startx - (conf.width + conf.actorMargin) / 2, + bounds.getVerticalPos(), + msg + ); } else if (msg.to === msg.from) { // Single-actor over - drawNote(diagram, startx, bounds.getVerticalPos(), msg) + drawNote(diagram, startx, bounds.getVerticalPos(), msg); } else { // Multi-actor over - forceWidth = Math.abs(startx - stopx) + conf.actorMargin - drawNote(diagram, (startx + stopx + conf.width - forceWidth) / 2, bounds.getVerticalPos(), msg, - forceWidth) + forceWidth = Math.abs(startx - stopx) + conf.actorMargin; + drawNote( + diagram, + (startx + stopx + conf.width - forceWidth) / 2, + bounds.getVerticalPos(), + msg, + forceWidth + ); } - break + break; case parser.yy.LINETYPE.ACTIVE_START: - bounds.newActivation(msg, diagram) - break + bounds.newActivation(msg, diagram); + break; case parser.yy.LINETYPE.ACTIVE_END: - activeEnd(msg, bounds.getVerticalPos()) - break + activeEnd(msg, bounds.getVerticalPos()); + break; case parser.yy.LINETYPE.LOOP_START: - bounds.bumpVerticalPos(conf.boxMargin) - bounds.newLoop(msg.message) - bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin) - break + bounds.bumpVerticalPos(conf.boxMargin); + bounds.newLoop(msg.message); + bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin); + break; case parser.yy.LINETYPE.LOOP_END: - loopData = bounds.endLoop() + loopData = bounds.endLoop(); - svgDraw.drawLoop(diagram, loopData, 'loop', conf) - bounds.bumpVerticalPos(conf.boxMargin) - break + svgDraw.drawLoop(diagram, loopData, 'loop', conf); + bounds.bumpVerticalPos(conf.boxMargin); + break; case parser.yy.LINETYPE.RECT_START: - bounds.bumpVerticalPos(conf.boxMargin) - bounds.newLoop(undefined, msg.message) - bounds.bumpVerticalPos(conf.boxMargin) - break + bounds.bumpVerticalPos(conf.boxMargin); + bounds.newLoop(undefined, msg.message); + bounds.bumpVerticalPos(conf.boxMargin); + break; case parser.yy.LINETYPE.RECT_END: - const rectData = bounds.endLoop() - svgDraw.drawBackgroundRect(diagram, rectData) - bounds.bumpVerticalPos(conf.boxMargin) - break + const rectData = bounds.endLoop(); + svgDraw.drawBackgroundRect(diagram, rectData); + bounds.bumpVerticalPos(conf.boxMargin); + break; case parser.yy.LINETYPE.OPT_START: - bounds.bumpVerticalPos(conf.boxMargin) - bounds.newLoop(msg.message) - bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin) - break + bounds.bumpVerticalPos(conf.boxMargin); + bounds.newLoop(msg.message); + bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin); + break; case parser.yy.LINETYPE.OPT_END: - loopData = bounds.endLoop() + loopData = bounds.endLoop(); - svgDraw.drawLoop(diagram, loopData, 'opt', conf) - bounds.bumpVerticalPos(conf.boxMargin) - break + svgDraw.drawLoop(diagram, loopData, 'opt', conf); + bounds.bumpVerticalPos(conf.boxMargin); + break; case parser.yy.LINETYPE.ALT_START: - bounds.bumpVerticalPos(conf.boxMargin) - bounds.newLoop(msg.message) - bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin) - break + bounds.bumpVerticalPos(conf.boxMargin); + bounds.newLoop(msg.message); + bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin); + break; case parser.yy.LINETYPE.ALT_ELSE: - bounds.bumpVerticalPos(conf.boxMargin) - loopData = bounds.addSectionToLoop(msg.message) - bounds.bumpVerticalPos(conf.boxMargin) - break + bounds.bumpVerticalPos(conf.boxMargin); + loopData = bounds.addSectionToLoop(msg.message); + bounds.bumpVerticalPos(conf.boxMargin); + break; case parser.yy.LINETYPE.ALT_END: - loopData = bounds.endLoop() + loopData = bounds.endLoop(); - svgDraw.drawLoop(diagram, loopData, 'alt', conf) - bounds.bumpVerticalPos(conf.boxMargin) - break + svgDraw.drawLoop(diagram, loopData, 'alt', conf); + bounds.bumpVerticalPos(conf.boxMargin); + break; case parser.yy.LINETYPE.PAR_START: - bounds.bumpVerticalPos(conf.boxMargin) - bounds.newLoop(msg.message) - bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin) - break + bounds.bumpVerticalPos(conf.boxMargin); + bounds.newLoop(msg.message); + bounds.bumpVerticalPos(conf.boxMargin + conf.boxTextMargin); + break; case parser.yy.LINETYPE.PAR_AND: - bounds.bumpVerticalPos(conf.boxMargin) - loopData = bounds.addSectionToLoop(msg.message) - bounds.bumpVerticalPos(conf.boxMargin) - break + bounds.bumpVerticalPos(conf.boxMargin); + loopData = bounds.addSectionToLoop(msg.message); + bounds.bumpVerticalPos(conf.boxMargin); + break; case parser.yy.LINETYPE.PAR_END: - loopData = bounds.endLoop() - svgDraw.drawLoop(diagram, loopData, 'par', conf) - bounds.bumpVerticalPos(conf.boxMargin) - break + loopData = bounds.endLoop(); + svgDraw.drawLoop(diagram, loopData, 'par', conf); + bounds.bumpVerticalPos(conf.boxMargin); + break; default: try { // lastMsg = msg - bounds.bumpVerticalPos(conf.messageMargin) - const fromBounds = actorFlowVerticaBounds(msg.from) - const toBounds = actorFlowVerticaBounds(msg.to) - const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0 - const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1 - startx = fromBounds[fromIdx] - stopx = toBounds[toIdx] + bounds.bumpVerticalPos(conf.messageMargin); + const fromBounds = actorFlowVerticaBounds(msg.from); + const toBounds = actorFlowVerticaBounds(msg.to); + const fromIdx = fromBounds[0] <= toBounds[0] ? 1 : 0; + const toIdx = fromBounds[0] < toBounds[0] ? 0 : 1; + startx = fromBounds[fromIdx]; + stopx = toBounds[toIdx]; - const verticalPos = bounds.getVerticalPos() - drawMessage(diagram, startx, stopx, verticalPos, msg, sequenceIndex) - const allBounds = fromBounds.concat(toBounds) - bounds.insert(Math.min.apply(null, allBounds), verticalPos, Math.max.apply(null, allBounds), verticalPos) + const verticalPos = bounds.getVerticalPos(); + drawMessage(diagram, startx, stopx, verticalPos, msg, sequenceIndex); + const allBounds = fromBounds.concat(toBounds); + bounds.insert( + Math.min.apply(null, allBounds), + verticalPos, + Math.max.apply(null, allBounds), + verticalPos + ); } catch (e) { - logger.error('error while drawing message', e) + logger.error('error while drawing message', e); } } // Increment sequence counter if msg.type is a line (and not another event like activation or note, etc) - if ([ - parser.yy.LINETYPE.SOLID_OPEN, - parser.yy.LINETYPE.DOTTED_OPEN, - parser.yy.LINETYPE.SOLID, - parser.yy.LINETYPE.DOTTED, - parser.yy.LINETYPE.SOLID_CROSS, - parser.yy.LINETYPE.DOTTED_CROSS - ].includes(msg.type)) { - sequenceIndex++ + if ( + [ + parser.yy.LINETYPE.SOLID_OPEN, + parser.yy.LINETYPE.DOTTED_OPEN, + parser.yy.LINETYPE.SOLID, + parser.yy.LINETYPE.DOTTED, + parser.yy.LINETYPE.SOLID_CROSS, + parser.yy.LINETYPE.DOTTED_CROSS + ].includes(msg.type) + ) { + sequenceIndex++; } - }) + }); if (conf.mirrorActors) { // Draw actors below diagram - bounds.bumpVerticalPos(conf.boxMargin * 2) - drawActors(diagram, actors, actorKeys, bounds.getVerticalPos()) + bounds.bumpVerticalPos(conf.boxMargin * 2); + drawActors(diagram, actors, actorKeys, bounds.getVerticalPos()); } - const box = bounds.getBounds() + const box = bounds.getBounds(); // Adjust line height of actor lines now that the height of the diagram is known - logger.debug('For line height fix Querying: #' + id + ' .actor-line') - const actorLines = d3.selectAll('#' + id + ' .actor-line') - actorLines.attr('y2', box.stopy) + logger.debug('For line height fix Querying: #' + id + ' .actor-line'); + const actorLines = d3.selectAll('#' + id + ' .actor-line'); + actorLines.attr('y2', box.stopy); - let height = box.stopy - box.starty + 2 * conf.diagramMarginY + let height = box.stopy - box.starty + 2 * conf.diagramMarginY; if (conf.mirrorActors) { - height = height - conf.boxMargin + conf.bottomMarginAdj + height = height - conf.boxMargin + conf.bottomMarginAdj; } - const width = (box.stopx - box.startx) + (2 * conf.diagramMarginX) + const width = box.stopx - box.startx + 2 * conf.diagramMarginX; if (title) { - diagram.append('text') + diagram + .append('text') .text(title) - .attr('x', ((box.stopx - box.startx) / 2) - (2 * conf.diagramMarginX)) - .attr('y', -25) + .attr('x', (box.stopx - box.startx) / 2 - 2 * conf.diagramMarginX) + .attr('y', -25); } if (conf.useMaxWidth) { - diagram.attr('height', '100%') - diagram.attr('width', '100%') - diagram.attr('style', 'max-width:' + (width) + 'px;') + diagram.attr('height', '100%'); + diagram.attr('width', '100%'); + diagram.attr('style', 'max-width:' + width + 'px;'); } else { - diagram.attr('height', height) - diagram.attr('width', width) + diagram.attr('height', height); + diagram.attr('width', width); } - const extraVertForTitle = title ? 40 : 0 - diagram.attr('viewBox', (box.startx - conf.diagramMarginX) + ' -' + (conf.diagramMarginY + extraVertForTitle) + ' ' + width + ' ' + (height + extraVertForTitle)) -} + const extraVertForTitle = title ? 40 : 0; + diagram.attr( + 'viewBox', + box.startx - + conf.diagramMarginX + + ' -' + + (conf.diagramMarginY + extraVertForTitle) + + ' ' + + width + + ' ' + + (height + extraVertForTitle) + ); +}; export default { bounds, drawActors, setConf, draw -} +}; From e14922f15c04701c9e8eb8a73747898e6e5c238d Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:55:20 -0700 Subject: [PATCH 04/13] #931 Aligning code standard --- src/diagrams/pie/parser/pie.spec.js | 57 +++++++------- src/diagrams/pie/pieDb.js | 48 ++++++------ src/diagrams/pie/pieRenderer.js | 115 +++++++++++++++------------- 3 files changed, 115 insertions(+), 105 deletions(-) diff --git a/src/diagrams/pie/parser/pie.spec.js b/src/diagrams/pie/parser/pie.spec.js index 0e9b80384..7902ce715 100644 --- a/src/diagrams/pie/parser/pie.spec.js +++ b/src/diagrams/pie/parser/pie.spec.js @@ -1,37 +1,36 @@ - /* eslint-env jasmine */ -import pieDb from '../pieDb' -import pie from './pie' -import { setConfig } from '../../../config' +import pieDb from '../pieDb'; +import pie from './pie'; +import { setConfig } from '../../../config'; setConfig({ securityLevel: 'strict' -}) +}); -describe('when parsing pie', function () { - beforeEach(function () { - pie.parser.yy = pieDb - pie.parser.yy.clear() - }) - it('should handle simple pie', function () { - const res = pie.parser.parse('pie \n"ash" : 60\n"bat" : 40\n') - const sections = pieDb.getSections() - console.log('sections: ', sections) - const section1 = sections['ash'] - expect(section1).toBe(60) - }) +describe('when parsing pie', function() { + beforeEach(function() { + pie.parser.yy = pieDb; + pie.parser.yy.clear(); + }); + it('should handle simple pie', function() { + const res = pie.parser.parse('pie \n"ash" : 60\n"bat" : 40\n'); + const sections = pieDb.getSections(); + console.log('sections: ', sections); + const section1 = sections['ash']; + expect(section1).toBe(60); + }); - it('should handle simple pie with positive decimal', function () { - const res = pie.parser.parse('pie \n"ash" : 60.67\n"bat" : 40\n') - const sections = pieDb.getSections() - console.log('sections: ', sections) - const section1 = sections['ash'] - expect(section1).toBe(60.67) - }) + it('should handle simple pie with positive decimal', function() { + const res = pie.parser.parse('pie \n"ash" : 60.67\n"bat" : 40\n'); + const sections = pieDb.getSections(); + console.log('sections: ', sections); + const section1 = sections['ash']; + expect(section1).toBe(60.67); + }); - it('should handle simple pie with negative decimal', function () { - expect(()=>{ + it('should handle simple pie with negative decimal', function() { + expect(() => { pie.parser.parse('pie \n"ash" : 60.67\n"bat" : 40..12\n'); - }).toThrowError(); - }) -}) + }).toThrowError(); + }); +}); diff --git a/src/diagrams/pie/pieDb.js b/src/diagrams/pie/pieDb.js index 8c1f294fe..d4572b547 100644 --- a/src/diagrams/pie/pieDb.js +++ b/src/diagrams/pie/pieDb.js @@ -1,40 +1,40 @@ /** * */ -import { logger } from '../../logger' +import { logger } from '../../logger'; -let sections = {} -let title = '' +let sections = {}; +let title = ''; -const addSection = function (id, value) { +const addSection = function(id, value) { if (typeof sections[id] === 'undefined') { - sections[id] = value - logger.debug('Added new section :', id) + sections[id] = value; + logger.debug('Added new section :', id); // console.log('Added new section:', id, value) } -} -const getSections = () => sections +}; +const getSections = () => sections; -const setTitle = function (txt) { - title = txt -} +const setTitle = function(txt) { + title = txt; +}; -const getTitle = function () { - return title -} -const cleanupValue = function (value) { +const getTitle = function() { + return title; +}; +const cleanupValue = function(value) { if (value.substring(0, 1) === ':') { - value = value.substring(1).trim() - return Number(value.trim()) + value = value.substring(1).trim(); + return Number(value.trim()); } else { - return Number(value.trim()) + return Number(value.trim()); } -} +}; -const clear = function () { - sections = {} - title = '' -} +const clear = function() { + sections = {}; + title = ''; +}; // export const parseError = (err, hash) => { // global.mermaidAPI.parseError(err, hash) // } @@ -47,4 +47,4 @@ export default { setTitle, getTitle // parseError -} +}; diff --git a/src/diagrams/pie/pieRenderer.js b/src/diagrams/pie/pieRenderer.js index a1d7ec30f..bdf857480 100644 --- a/src/diagrams/pie/pieRenderer.js +++ b/src/diagrams/pie/pieRenderer.js @@ -1,83 +1,87 @@ /** * Created by AshishJ on 11-09-2019. */ -import * as d3 from 'd3' -import pieData from './pieDb' -import pieParser from './parser/pie' -import { logger } from '../../logger' +import * as d3 from 'd3'; +import pieData from './pieDb'; +import pieParser from './parser/pie'; +import { logger } from '../../logger'; -const conf = { -} -export const setConf = function (cnf) { - const keys = Object.keys(cnf) +const conf = {}; +export const setConf = function(cnf) { + const keys = Object.keys(cnf); - keys.forEach(function (key) { - conf[key] = cnf[key] - }) -} + keys.forEach(function(key) { + conf[key] = cnf[key]; + }); +}; /** * Draws a Pie Chart with the data given in text. * @param text * @param id */ -let w +let w; export const draw = (txt, id, ver) => { try { - const parser = pieParser.parser - parser.yy = pieData - logger.debug('Rendering info diagram\n' + txt) + const parser = pieParser.parser; + parser.yy = pieData; + logger.debug('Rendering info diagram\n' + txt); // Parse the Pie Chart definition - parser.yy.clear() - parser.parse(txt) - logger.debug('Parsed info diagram') - const elem = document.getElementById(id) - w = elem.parentElement.offsetWidth + parser.yy.clear(); + parser.parse(txt); + logger.debug('Parsed info diagram'); + const elem = document.getElementById(id); + w = elem.parentElement.offsetWidth; if (typeof w === 'undefined') { - w = 1200 + w = 1200; } if (typeof conf.useWidth !== 'undefined') { - w = conf.useWidth + w = conf.useWidth; } - const h = 450 - elem.setAttribute('height', '100%') + const h = 450; + elem.setAttribute('height', '100%'); // Set viewBox - elem.setAttribute('viewBox', '0 0 ' + w + ' ' + h) + elem.setAttribute('viewBox', '0 0 ' + w + ' ' + h); // Fetch the default direction, use TD if none was found - var width = w// 450 - var height = 450 - var margin = 40 + var width = w; // 450 + var height = 450; + var margin = 40; - var radius = Math.min(width, height) / 2 - margin + var radius = Math.min(width, height) / 2 - margin; - var svg = d3.select('#' + id).append('svg') + var svg = d3 + .select('#' + id) + .append('svg') .attr('width', width) .attr('height', height) .append('g') - .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')') + .attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); - var data = pieData.getSections() - logger.info(data) + var data = pieData.getSections(); + logger.info(data); // set the color scale - var color = d3.scaleOrdinal() + var color = d3 + .scaleOrdinal() .domain(data) - .range(d3.schemeSet2) + .range(d3.schemeSet2); // Compute the position of each group on the pie: - var pie = d3.pie() - .value(function (d) { return d.value }) - var dataReady = pie(d3.entries(data)) + var pie = d3.pie().value(function(d) { + return d.value; + }); + var dataReady = pie(d3.entries(data)); // Now I know that group A goes from 0 degrees to x degrees and so on. // shape helper to build arcs: - var arcGenerator = d3.arc() + var arcGenerator = d3 + .arc() .innerRadius(0) - .outerRadius(radius) + .outerRadius(radius); // Build the pie chart: Basically, each part of the pie is a path that we build using the arc function. svg @@ -86,10 +90,12 @@ export const draw = (txt, id, ver) => { .enter() .append('path') .attr('d', arcGenerator) - .attr('fill', function (d) { return (color(d.data.key)) }) + .attr('fill', function(d) { + return color(d.data.key); + }) .attr('stroke', 'black') .style('stroke-width', '2px') - .style('opacity', 0.7) + .style('opacity', 0.7); // Now add the annotation. Use the centroid method to get the best coordinates svg @@ -97,23 +103,28 @@ export const draw = (txt, id, ver) => { .data(dataReady) .enter() .append('text') - .text(function (d) { return d.data.key }) - .attr('transform', function (d) { return 'translate(' + arcGenerator.centroid(d) + ')' }) + .text(function(d) { + return d.data.key; + }) + .attr('transform', function(d) { + return 'translate(' + arcGenerator.centroid(d) + ')'; + }) .style('text-anchor', 'middle') - .style('font-size', 17) + .style('font-size', 17); - svg.append('text') + svg + .append('text') .text(parser.yy.getTitle()) .attr('x', 0) .attr('y', -(h - 50) / 2) - .attr('class', 'pieTitleText') + .attr('class', 'pieTitleText'); } catch (e) { - logger.error('Error while rendering info diagram') - logger.error(e.message) + logger.error('Error while rendering info diagram'); + logger.error(e.message); } -} +}; export default { setConf, draw -} +}; From e67b8c86d6d7fed8a9b0649807f70577fddd5b31 Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:55:31 -0700 Subject: [PATCH 05/13] #931 Aligning code standard --- src/diagrams/info/info.spec.js | 22 ++++++------- src/diagrams/info/infoDb.js | 26 ++++++++-------- src/diagrams/info/infoRenderer.js | 51 +++++++++++++++---------------- 3 files changed, 49 insertions(+), 50 deletions(-) diff --git a/src/diagrams/info/info.spec.js b/src/diagrams/info/info.spec.js index 5b7c50577..502e4bdf8 100644 --- a/src/diagrams/info/info.spec.js +++ b/src/diagrams/info/info.spec.js @@ -1,15 +1,15 @@ /* eslint-env jasmine */ -describe('when parsing an info graph it', function () { - var ex - beforeEach(function () { - ex = require('./parser/info').parser - ex.yy = require('./infoDb') - }) +describe('when parsing an info graph it', function() { + var ex; + beforeEach(function() { + ex = require('./parser/info').parser; + ex.yy = require('./infoDb'); + }); - it('should handle an info definition', function () { + it('should handle an info definition', function() { var str = `info - showInfo` + showInfo`; - ex.parse(str) - }) -}) + ex.parse(str); + }); +}); diff --git a/src/diagrams/info/infoDb.js b/src/diagrams/info/infoDb.js index cd79b024c..2253c819e 100644 --- a/src/diagrams/info/infoDb.js +++ b/src/diagrams/info/infoDb.js @@ -1,27 +1,27 @@ /** * Created by knut on 15-01-14. */ -import { logger } from '../../logger' +import { logger } from '../../logger'; -var message = '' -var info = false +var message = ''; +var info = false; export const setMessage = txt => { - logger.debug('Setting message to: ' + txt) - message = txt -} + logger.debug('Setting message to: ' + txt); + message = txt; +}; export const getMessage = () => { - return message -} + return message; +}; export const setInfo = inf => { - info = inf -} + info = inf; +}; export const getInfo = () => { - return info -} + return info; +}; // export const parseError = (err, hash) => { // global.mermaidAPI.parseError(err, hash) @@ -33,4 +33,4 @@ export default { setInfo, getInfo // parseError -} +}; diff --git a/src/diagrams/info/infoRenderer.js b/src/diagrams/info/infoRenderer.js index dc4d7066e..8aceffb65 100644 --- a/src/diagrams/info/infoRenderer.js +++ b/src/diagrams/info/infoRenderer.js @@ -1,20 +1,19 @@ /** * Created by knut on 14-12-11. */ -import * as d3 from 'd3' -import db from './infoDb' -import infoParser from './parser/info' -import { logger } from '../../logger' +import * as d3 from 'd3'; +import db from './infoDb'; +import infoParser from './parser/info'; +import { logger } from '../../logger'; -const conf = { -} -export const setConf = function (cnf) { - const keys = Object.keys(cnf) +const conf = {}; +export const setConf = function(cnf) { + const keys = Object.keys(cnf); - keys.forEach(function (key) { - conf[key] = cnf[key] - }) -} + keys.forEach(function(key) { + conf[key] = cnf[key]; + }); +}; /** * Draws a an info picture in the tag with id: id based on the graph definition in text. @@ -23,16 +22,16 @@ export const setConf = function (cnf) { */ export const draw = (txt, id, ver) => { try { - const parser = infoParser.parser - parser.yy = db - logger.debug('Renering info diagram\n' + txt) + const parser = infoParser.parser; + parser.yy = db; + logger.debug('Renering info diagram\n' + txt); // Parse the graph definition - parser.parse(txt) - logger.debug('Parsed info diagram') + parser.parse(txt); + logger.debug('Parsed info diagram'); // Fetch the default direction, use TD if none was found - const svg = d3.select('#' + id) + const svg = d3.select('#' + id); - const g = svg.append('g') + const g = svg.append('g'); g.append('text') // text label for the x axis .attr('x', 100) @@ -40,18 +39,18 @@ export const draw = (txt, id, ver) => { .attr('class', 'version') .attr('font-size', '32px') .style('text-anchor', 'middle') - .text('v ' + ver) + .text('v ' + ver); - svg.attr('height', 100) - svg.attr('width', 400) + svg.attr('height', 100); + svg.attr('width', 400); // svg.attr('viewBox', '0 0 300 150'); } catch (e) { - logger.error('Error while rendering info diagram') - logger.error(e.message) + logger.error('Error while rendering info diagram'); + logger.error(e.message); } -} +}; export default { setConf, draw -} +}; From d2f082b2e2a42387783b0bc42b4194c691815668 Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:55:56 -0700 Subject: [PATCH 06/13] #931 Replacing linter --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 72c90f7f7..5cd538f71 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "build:watch": "yarn build --watch", "minify": "minify ./dist/mermaid.js > ./dist/mermaid.min.js", "release": "yarn build -p --config webpack.config.prod.babel.js", - "lint": "standard", + "lint": "eslint src", "e2e:depr": "yarn lint && jest e2e --config e2e/jest.config.js", "cypress": "percy exec -- cypress run", "e2e": "start-server-and-test dev http://localhost:9000/ cypress", From 0890ba0fdd68d088423159d9f4bd331e1ca81e2f Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:56:20 -0700 Subject: [PATCH 07/13] #931 replacing linter --- yarn.lock | 273 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 267 insertions(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index c2e24ae0b..8f64c4adb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1528,6 +1528,11 @@ acorn-jsx@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" +acorn-jsx@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" + integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw== + acorn-walk@^6.0.1: version "6.1.1" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" @@ -1540,6 +1545,11 @@ acorn@^6.0.1, acorn@^6.0.2: version "6.0.4" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.0.4.tgz#77377e7353b72ec5104550aa2d2097a2fd40b754" +acorn@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a" + integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ== + agent-base@^4.1.0: version "4.2.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" @@ -1575,6 +1585,16 @@ ajv@^6.1.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" +ajv@^6.10.0, ajv@^6.10.2: + version "6.10.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" + integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== + dependencies: + fast-deep-equal "^2.0.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -1591,9 +1611,10 @@ ansi-escapes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" -ansi-escapes@^3.1.0: +ansi-escapes@^3.1.0, ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" + integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== ansi-html@0.0.7, ansi-html@^0.0.7: version "0.0.7" @@ -2383,6 +2404,11 @@ callsites@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camel-case@3.0.x: version "3.0.0" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" @@ -2504,6 +2530,11 @@ chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + check-more-types@2.24.0: version "2.24.0" resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" @@ -3394,9 +3425,10 @@ debug@3.2.6, debug@^3.2.5, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@4.1.1, debug@^4.1.1: +debug@4.1.1, debug@^4.0.1, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" @@ -3627,6 +3659,13 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + documentation@^12.0.1: version "12.0.1" resolved "https://registry.yarnpkg.com/documentation/-/documentation-12.0.1.tgz#4abe263d5415f3ed7ee737829921ef6159e6a335" @@ -3899,6 +3938,13 @@ escodegen@^1.9.1: optionalDependencies: source-map "~0.6.1" +eslint-config-prettier@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.3.0.tgz#e73b48e59dc49d950843f3eb96d519e2248286a3" + integrity sha512-EWaGjlDAZRzVFveh2Jsglcere2KK5CJBhkNSa1xs3KfMUGdRiT7lG089eqPdvlzWHpAqaekubOsOMu8W8Yk71A== + dependencies: + get-stdin "^6.0.0" + eslint-config-standard-jsx@6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-6.0.2.tgz#90c9aa16ac2c4f8970c13fc7efc608bacd02da70" @@ -3954,6 +4000,13 @@ eslint-plugin-node@~7.0.1: resolve "^1.8.1" semver "^5.5.0" +eslint-plugin-prettier@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.0.tgz#8695188f95daa93b0dc54b249347ca3b79c4686d" + integrity sha512-XWX2yVuwVNLOUhQijAkXz+rMPPoCr7WFiAl8ig6I7Xn+pPVhDhzg4DxHpmbeb0iqjO9UronEA3Tb09ChnFVHHA== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-plugin-promise@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.0.1.tgz#2d074b653f35a23d1ba89d8e976a985117d1c6a2" @@ -3979,14 +4032,77 @@ eslint-scope@^4.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^1.3.0, eslint-utils@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.3.1.tgz#9a851ba89ee7c460346f97cf8939c7298827e512" +eslint-utils@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" + integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== + dependencies: + eslint-visitor-keys "^1.0.0" + eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" +eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== + +eslint@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.3.0.tgz#1f1a902f67bfd4c354e7288b81e40654d927eb6a" + integrity sha512-ZvZTKaqDue+N8Y9g0kp6UPZtS4FSY3qARxBs7p4f0H0iof381XHduqVerFWtK8DPtKmemqbqCFENWSQgPR/Gow== + dependencies: + "@babel/code-frame" "^7.0.0" + ajv "^6.10.0" + chalk "^2.1.0" + cross-spawn "^6.0.5" + debug "^4.0.1" + doctrine "^3.0.0" + eslint-scope "^5.0.0" + eslint-utils "^1.4.2" + eslint-visitor-keys "^1.1.0" + espree "^6.1.1" + esquery "^1.0.1" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^11.7.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + inquirer "^6.4.1" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.14" + minimatch "^3.0.4" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + progress "^2.0.0" + regexpp "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + eslint@~5.4.0: version "5.4.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.4.0.tgz#d068ec03006bb9e06b429dc85f7e46c1b69fac62" @@ -4038,6 +4154,15 @@ espree@^4.0.0: acorn-jsx "^5.0.0" eslint-visitor-keys "^1.0.0" +espree@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" + integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== + dependencies: + acorn "^7.0.0" + acorn-jsx "^5.0.2" + eslint-visitor-keys "^1.1.0" + esprima@1.1.x, esprima@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.1.1.tgz#5b6f1547f4d102e670e140c509be6771d6aeb549" @@ -4289,6 +4414,15 @@ external-editor@^2.1.0: iconv-lite "^0.4.17" tmp "^0.0.33" +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -4337,6 +4471,11 @@ fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + fast-glob@^3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.0.4.tgz#d484a41005cb6faeb399b951fd1bd70ddaebb602" @@ -4420,6 +4559,13 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + filename-regex@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" @@ -4537,6 +4683,20 @@ flat-cache@^1.2.1: rimraf "~2.6.2" write "^0.2.1" +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" + integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" @@ -5260,7 +5420,7 @@ hyperlinker@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hyperlinker/-/hyperlinker-1.0.0.tgz#23dc9e38a206b208ee49bc2d6c8ef47027df0c0e" -iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.4: +iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" dependencies: @@ -5300,9 +5460,10 @@ ignore@^3.0.9: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" -ignore@^4.0.2: +ignore@^4.0.2, ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== ignore@^5.1.1: version "5.1.4" @@ -5315,6 +5476,14 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" +import-fresh@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" + integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + import-local@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" @@ -5396,6 +5565,25 @@ inquirer@^5.2.0: strip-ansi "^4.0.0" through "^2.3.6" +inquirer@^6.4.1: + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== + dependencies: + ansi-escapes "^3.2.0" + chalk "^2.4.2" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^3.0.3" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" + run-async "^2.2.0" + rxjs "^6.4.0" + string-width "^2.1.0" + strip-ansi "^5.1.0" + through "^2.3.6" + internal-ip@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907" @@ -6661,9 +6849,10 @@ lodash@^4.0.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, version "4.17.13" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.13.tgz#0bdc3a6adc873d2f4e0c4bac285df91b64fc7b93" -lodash@^4.17.13: +lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" + integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== log-driver@^1.2.7: version "1.2.7" @@ -7699,6 +7888,13 @@ param-case@2.1.x: dependencies: no-case "^2.2.0" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parse-asn1@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.1.tgz#f6bf293818332bd0dab54efb16087724745e6ca8" @@ -8062,6 +8258,18 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^1.18.2: + version "1.18.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea" + integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw== + pretty-format@^23.6.0: version "23.6.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760" @@ -8804,6 +9012,11 @@ resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-options@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" @@ -8856,7 +9069,7 @@ reusify@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" -rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.2: +rimraf@2, rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" dependencies: @@ -8907,6 +9120,13 @@ rxjs@^5.0.0-beta.11, rxjs@^5.5.2: dependencies: symbol-observable "1.0.1" +rxjs@^6.4.0: + version "6.5.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a" + integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA== + dependencies: + tslib "^1.9.0" + safe-buffer@5.1.2, safe-buffer@^5.1.1, safe-buffer@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -9036,6 +9256,11 @@ semver@^6.1.1: version "6.2.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db" +semver@^6.1.2: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -9199,6 +9424,15 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + slugify@^1.3.1: version "1.3.4" resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.3.4.tgz#78d2792d7222b55cd9fc81fa018df99af779efeb" @@ -9648,6 +9882,11 @@ strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" +strip-json-comments@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" + integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== + subarg@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" @@ -9708,6 +9947,16 @@ table@^4.0.3: slice-ansi "1.0.0" string-width "^2.1.1" +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + tapable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.0.0.tgz#cbb639d9002eed9c6b5975eb20598d7936f1f9f2" @@ -10253,6 +10502,11 @@ v8-compile-cache@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.2.tgz#a428b28bb26790734c4fc8bc9fa106fccebf6a6c" +v8-compile-cache@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== + validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" @@ -10687,6 +10941,13 @@ write-file-atomic@^2.1.0: imurmurhash "^0.1.4" signal-exit "^3.0.2" +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" From a2e3f3d9006d731800e9742688d4466319aa1a2c Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:56:54 -0700 Subject: [PATCH 08/13] #931 Reformatting code for gitGraph --- src/diagrams/git/gitGraphAst.js | 292 ++++++++++--------- src/diagrams/git/gitGraphParser.spec.js | 310 ++++++++++---------- src/diagrams/git/gitGraphRenderer.js | 363 ++++++++++++++---------- 3 files changed, 510 insertions(+), 455 deletions(-) diff --git a/src/diagrams/git/gitGraphAst.js b/src/diagrams/git/gitGraphAst.js index f7338c5ed..85e8f7905 100644 --- a/src/diagrams/git/gitGraphAst.js +++ b/src/diagrams/git/gitGraphAst.js @@ -1,98 +1,100 @@ -import _ from 'lodash' +import _ from 'lodash'; -import { logger } from '../../logger' +import { logger } from '../../logger'; -let commits = {} -let head = null -let branches = { 'master': head } -let curBranch = 'master' -let direction = 'LR' -let seq = 0 +let commits = {}; +let head = null; +let branches = { master: head }; +let curBranch = 'master'; +let direction = 'LR'; +let seq = 0; -function getRandomInt (min, max) { - return Math.floor(Math.random() * (max - min)) + min +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min)) + min; } -function getId () { - const pool = '0123456789abcdef' - let id = '' +function getId() { + const pool = '0123456789abcdef'; + let id = ''; for (let i = 0; i < 7; i++) { - id += pool[getRandomInt(0, 16)] + id += pool[getRandomInt(0, 16)]; } - return id + return id; } -function isfastforwardable (currentCommit, otherCommit) { - logger.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id) +function isfastforwardable(currentCommit, otherCommit) { + logger.debug('Entering isfastforwardable:', currentCommit.id, otherCommit.id); while (currentCommit.seq <= otherCommit.seq && currentCommit !== otherCommit) { // only if other branch has more commits - if (otherCommit.parent == null) break + if (otherCommit.parent == null) break; if (Array.isArray(otherCommit.parent)) { - logger.debug('In merge commit:', otherCommit.parent) - return isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) || + logger.debug('In merge commit:', otherCommit.parent); + return ( + isfastforwardable(currentCommit, commits[otherCommit.parent[0]]) || isfastforwardable(currentCommit, commits[otherCommit.parent[1]]) + ); } else { - otherCommit = commits[otherCommit.parent] + otherCommit = commits[otherCommit.parent]; } } - logger.debug(currentCommit.id, otherCommit.id) - return currentCommit.id === otherCommit.id + logger.debug(currentCommit.id, otherCommit.id); + return currentCommit.id === otherCommit.id; } -function isReachableFrom (currentCommit, otherCommit) { - const currentSeq = currentCommit.seq - const otherSeq = otherCommit.seq - if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit) - return false +function isReachableFrom(currentCommit, otherCommit) { + const currentSeq = currentCommit.seq; + const otherSeq = otherCommit.seq; + if (currentSeq > otherSeq) return isfastforwardable(otherCommit, currentCommit); + return false; } -export const setDirection = function (dir) { - direction = dir -} -let options = {} -export const setOptions = function (rawOptString) { - logger.debug('options str', rawOptString) - rawOptString = rawOptString && rawOptString.trim() - rawOptString = rawOptString || '{}' +export const setDirection = function(dir) { + direction = dir; +}; +let options = {}; +export const setOptions = function(rawOptString) { + logger.debug('options str', rawOptString); + rawOptString = rawOptString && rawOptString.trim(); + rawOptString = rawOptString || '{}'; try { - options = JSON.parse(rawOptString) + options = JSON.parse(rawOptString); } catch (e) { - logger.error('error while parsing gitGraph options', e.message) + logger.error('error while parsing gitGraph options', e.message); } -} +}; -export const getOptions = function () { - return options -} +export const getOptions = function() { + return options; +}; -export const commit = function (msg) { +export const commit = function(msg) { const commit = { id: getId(), message: msg, seq: seq++, parent: head == null ? null : head.id - } - head = commit - commits[commit.id] = commit - branches[curBranch] = commit.id - logger.debug('in pushCommit ' + commit.id) -} + }; + head = commit; + commits[commit.id] = commit; + branches[curBranch] = commit.id; + logger.debug('in pushCommit ' + commit.id); +}; -export const branch = function (name) { - branches[name] = head != null ? head.id : null - logger.debug('in createBranch') -} +export const branch = function(name) { + branches[name] = head != null ? head.id : null; + logger.debug('in createBranch'); +}; -export const merge = function (otherBranch) { - const currentCommit = commits[branches[curBranch]] - const otherCommit = commits[branches[otherBranch]] +export const merge = function(otherBranch) { + const currentCommit = commits[branches[curBranch]]; + const otherCommit = commits[branches[otherBranch]]; if (isReachableFrom(currentCommit, otherCommit)) { - logger.debug('Already merged') - return + logger.debug('Already merged'); + return; } if (isfastforwardable(currentCommit, otherCommit)) { - branches[curBranch] = branches[otherBranch] - head = commits[branches[curBranch]] + branches[curBranch] = branches[otherBranch]; + head = commits[branches[curBranch]]; } else { // create merge commit const commit = { @@ -100,113 +102,125 @@ export const merge = function (otherBranch) { message: 'merged branch ' + otherBranch + ' into ' + curBranch, seq: seq++, parent: [head == null ? null : head.id, branches[otherBranch]] - } - head = commit - commits[commit.id] = commit - branches[curBranch] = commit.id + }; + head = commit; + commits[commit.id] = commit; + branches[curBranch] = commit.id; } - logger.debug(branches) - logger.debug('in mergeBranch') -} + logger.debug(branches); + logger.debug('in mergeBranch'); +}; -export const checkout = function (branch) { - logger.debug('in checkout') - curBranch = branch - const id = branches[curBranch] - head = commits[id] -} +export const checkout = function(branch) { + logger.debug('in checkout'); + curBranch = branch; + const id = branches[curBranch]; + head = commits[id]; +}; -export const reset = function (commitRef) { - logger.debug('in reset', commitRef) - const ref = commitRef.split(':')[0] - let parentCount = parseInt(commitRef.split(':')[1]) - let commit = ref === 'HEAD' ? head : commits[branches[ref]] - logger.debug(commit, parentCount) +export const reset = function(commitRef) { + logger.debug('in reset', commitRef); + const ref = commitRef.split(':')[0]; + let parentCount = parseInt(commitRef.split(':')[1]); + let commit = ref === 'HEAD' ? head : commits[branches[ref]]; + logger.debug(commit, parentCount); while (parentCount > 0) { - commit = commits[commit.parent] - parentCount-- + commit = commits[commit.parent]; + parentCount--; if (!commit) { - const err = 'Critical error - unique parent commit not found during reset' - logger.error(err) - throw err + const err = 'Critical error - unique parent commit not found during reset'; + logger.error(err); + throw err; } } - head = commit - branches[curBranch] = commit.id -} + head = commit; + branches[curBranch] = commit.id; +}; -function upsert (arr, key, newval) { - const index = arr.indexOf(key) +function upsert(arr, key, newval) { + const index = arr.indexOf(key); if (index === -1) { - arr.push(newval) + arr.push(newval); } else { - arr.splice(index, 1, newval) + arr.splice(index, 1, newval); } } -function prettyPrintCommitHistory (commitArr) { - const commit = _.maxBy(commitArr, 'seq') - let line = '' - commitArr.forEach(function (c) { +function prettyPrintCommitHistory(commitArr) { + const commit = _.maxBy(commitArr, 'seq'); + let line = ''; + commitArr.forEach(function(c) { if (c === commit) { - line += '\t*' + line += '\t*'; } else { - line += '\t|' + line += '\t|'; } - }) - const label = [line, commit.id, commit.seq] + }); + const label = [line, commit.id, commit.seq]; for (let branch in branches) { - if (branches[branch] === commit.id) label.push(branch) + if (branches[branch] === commit.id) label.push(branch); } - logger.debug(label.join(' ')) + logger.debug(label.join(' ')); if (Array.isArray(commit.parent)) { - const newCommit = commits[commit.parent[0]] - upsert(commitArr, commit, newCommit) - commitArr.push(commits[commit.parent[1]]) + const newCommit = commits[commit.parent[0]]; + upsert(commitArr, commit, newCommit); + commitArr.push(commits[commit.parent[1]]); } else if (commit.parent == null) { - return + return; } else { - const nextCommit = commits[commit.parent] - upsert(commitArr, commit, nextCommit) + const nextCommit = commits[commit.parent]; + upsert(commitArr, commit, nextCommit); } - commitArr = _.uniqBy(commitArr, 'id') - prettyPrintCommitHistory(commitArr) + commitArr = _.uniqBy(commitArr, 'id'); + prettyPrintCommitHistory(commitArr); } -export const prettyPrint = function () { - logger.debug(commits) - const node = getCommitsArray()[0] - prettyPrintCommitHistory([node]) -} +export const prettyPrint = function() { + logger.debug(commits); + const node = getCommitsArray()[0]; + prettyPrintCommitHistory([node]); +}; -export const clear = function () { - commits = {} - head = null - branches = { 'master': head } - curBranch = 'master' - seq = 0 -} +export const clear = function() { + commits = {}; + head = null; + branches = { master: head }; + curBranch = 'master'; + seq = 0; +}; -export const getBranchesAsObjArray = function () { - const branchArr = [] +export const getBranchesAsObjArray = function() { + const branchArr = []; for (let branch in branches) { - branchArr.push({ name: branch, commit: commits[branches[branch]] }) + branchArr.push({ name: branch, commit: commits[branches[branch]] }); } - return branchArr -} + return branchArr; +}; -export const getBranches = function () { return branches } -export const getCommits = function () { return commits } -export const getCommitsArray = function () { - const commitArr = Object.keys(commits).map(function (key) { - return commits[key] - }) - commitArr.forEach(function (o) { logger.debug(o.id) }) - return _.orderBy(commitArr, ['seq'], ['desc']) -} -export const getCurrentBranch = function () { return curBranch } -export const getDirection = function () { return direction } -export const getHead = function () { return head } +export const getBranches = function() { + return branches; +}; +export const getCommits = function() { + return commits; +}; +export const getCommitsArray = function() { + const commitArr = Object.keys(commits).map(function(key) { + return commits[key]; + }); + commitArr.forEach(function(o) { + logger.debug(o.id); + }); + return _.orderBy(commitArr, ['seq'], ['desc']); +}; +export const getCurrentBranch = function() { + return curBranch; +}; +export const getDirection = function() { + return direction; +}; +export const getHead = function() { + return head; +}; export default { setDirection, @@ -226,4 +240,4 @@ export default { getCurrentBranch, getDirection, getHead -} +}; diff --git a/src/diagrams/git/gitGraphParser.spec.js b/src/diagrams/git/gitGraphParser.spec.js index aba2812d9..6afd7f876 100644 --- a/src/diagrams/git/gitGraphParser.spec.js +++ b/src/diagrams/git/gitGraphParser.spec.js @@ -1,201 +1,186 @@ /* eslint-env jasmine */ -import gitGraphAst from './gitGraphAst' -import { parser } from './parser/gitGraph' +import gitGraphAst from './gitGraphAst'; +import { parser } from './parser/gitGraph'; -describe('when parsing a gitGraph', function () { - beforeEach(function () { - parser.yy = gitGraphAst - parser.yy.clear() - }) - it('should handle a gitGraph defintion', function () { - const str = 'gitGraph:\n' + - 'commit\n' +describe('when parsing a gitGraph', function() { + beforeEach(function() { + parser.yy = gitGraphAst; + parser.yy.clear(); + }); + it('should handle a gitGraph defintion', function() { + const str = 'gitGraph:\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('LR') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should handle a gitGraph defintion with empty options', function () { - const str = 'gitGraph:\n' + - 'options\n' + - 'end\n' + - 'commit\n' + it('should handle a gitGraph defintion with empty options', function() { + const str = 'gitGraph:\n' + 'options\n' + 'end\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(parser.yy.getOptions()).toEqual({}) - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('LR') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + expect(parser.yy.getOptions()).toEqual({}); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should handle a gitGraph defintion with valid options', function () { - const str = 'gitGraph:\n' + - 'options\n' + - '{"key": "value"}\n' + - 'end\n' + - 'commit\n' + it('should handle a gitGraph defintion with valid options', function() { + const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"}\n' + 'end\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() - expect(parser.yy.getOptions()['key']).toBe('value') - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('LR') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + parser.parse(str); + const commits = parser.yy.getCommits(); + expect(parser.yy.getOptions()['key']).toBe('value'); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should not fail on a gitGraph with malformed json', function () { - const str = 'gitGraph:\n' + - 'options\n' + - '{"key": "value"\n' + - 'end\n' + - 'commit\n' + it('should not fail on a gitGraph with malformed json', function() { + const str = 'gitGraph:\n' + 'options\n' + '{"key": "value"\n' + 'end\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('LR') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + parser.parse(str); + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('LR'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should handle set direction', function () { - const str = 'gitGraph BT:\n' + - 'commit\n' + it('should handle set direction', function() { + const str = 'gitGraph BT:\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(1) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getDirection()).toBe('BT') - expect(Object.keys(parser.yy.getBranches()).length).toBe(1) - }) + expect(Object.keys(commits).length).toBe(1); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getDirection()).toBe('BT'); + expect(Object.keys(parser.yy.getBranches()).length).toBe(1); + }); - it('should checkout a branch', function () { - const str = 'gitGraph:\n' + - 'branch new\n' + - 'checkout new\n' + it('should checkout a branch', function() { + const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(0) - expect(parser.yy.getCurrentBranch()).toBe('new') - }) + expect(Object.keys(commits).length).toBe(0); + expect(parser.yy.getCurrentBranch()).toBe('new'); + }); - it('should add commits to checked out branch', function () { - const str = 'gitGraph:\n' + - 'branch new\n' + - 'checkout new\n' + - 'commit\n' + - 'commit\n' + it('should add commits to checked out branch', function() { + const str = 'gitGraph:\n' + 'branch new\n' + 'checkout new\n' + 'commit\n' + 'commit\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(2) - expect(parser.yy.getCurrentBranch()).toBe('new') - const branchCommit = parser.yy.getBranches()['new'] - expect(branchCommit).not.toBeNull() - expect(commits[branchCommit].parent).not.toBeNull() - }) - it('should handle commit with args', function () { - const str = 'gitGraph:\n' + - 'commit "a commit"\n' + expect(Object.keys(commits).length).toBe(2); + expect(parser.yy.getCurrentBranch()).toBe('new'); + const branchCommit = parser.yy.getBranches()['new']; + expect(branchCommit).not.toBeNull(); + expect(commits[branchCommit].parent).not.toBeNull(); + }); + it('should handle commit with args', function() { + const str = 'gitGraph:\n' + 'commit "a commit"\n'; - parser.parse(str) - const commits = parser.yy.getCommits() + parser.parse(str); + const commits = parser.yy.getCommits(); - expect(Object.keys(commits).length).toBe(1) - const key = Object.keys(commits)[0] - expect(commits[key].message).toBe('a commit') - expect(parser.yy.getCurrentBranch()).toBe('master') - }) + expect(Object.keys(commits).length).toBe(1); + const key = Object.keys(commits)[0]; + expect(commits[key].message).toBe('a commit'); + expect(parser.yy.getCurrentBranch()).toBe('master'); + }); - it('it should reset a branch', function () { - const str = 'gitGraph:\n' + + it('it should reset a branch', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + 'commit\n' + - 'reset master\n' + 'reset master\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(3) - expect(parser.yy.getCurrentBranch()).toBe('newbranch') - expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); + }); - it('reset can take an argument', function () { - const str = 'gitGraph:\n' + + it('reset can take an argument', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + 'commit\n' + - 'reset master^\n' + 'reset master^\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(3) - expect(parser.yy.getCurrentBranch()).toBe('newbranch') - const master = commits[parser.yy.getBranches()['master']] - expect(parser.yy.getHead().id).toEqual(master.parent) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + const master = commits[parser.yy.getBranches()['master']]; + expect(parser.yy.getHead().id).toEqual(master.parent); + }); - it('it should handle fast forwardable merges', function () { - const str = 'gitGraph:\n' + + it('it should handle fast forwardable merges', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + 'commit\n' + 'commit\n' + 'checkout master\n' + - 'merge newbranch\n' + 'merge newbranch\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(3) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); + }); - it('it should handle cases when merge is a noop', function () { - const str = 'gitGraph:\n' + + it('it should handle cases when merge is a noop', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + 'commit\n' + 'commit\n' + - 'merge master\n' + 'merge master\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(3) - expect(parser.yy.getCurrentBranch()).toBe('newbranch') - expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(3); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['newbranch']); + }); - it('it should handle merge with 2 parents', function () { - const str = 'gitGraph:\n' + + it('it should handle merge with 2 parents', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + @@ -203,19 +188,20 @@ describe('when parsing a gitGraph', function () { 'commit\n' + 'checkout master\n' + 'commit\n' + - 'merge newbranch\n' + 'merge newbranch\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(5) - expect(parser.yy.getCurrentBranch()).toBe('master') - expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']) - }) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(5); + expect(parser.yy.getCurrentBranch()).toBe('master'); + expect(parser.yy.getBranches()['newbranch']).not.toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']); + }); - it('it should handle ff merge when history walk has two parents (merge commit)', function () { - const str = 'gitGraph:\n' + + it('it should handle ff merge when history walk has two parents (merge commit)', function() { + const str = + 'gitGraph:\n' + 'commit\n' + 'branch newbranch\n' + 'checkout newbranch\n' + @@ -226,16 +212,16 @@ describe('when parsing a gitGraph', function () { 'merge newbranch\n' + 'commit\n' + 'checkout newbranch\n' + - 'merge master\n' + 'merge master\n'; - parser.parse(str) + parser.parse(str); - const commits = parser.yy.getCommits() - expect(Object.keys(commits).length).toBe(6) - expect(parser.yy.getCurrentBranch()).toBe('newbranch') - expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']) - expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']) + const commits = parser.yy.getCommits(); + expect(Object.keys(commits).length).toBe(6); + expect(parser.yy.getCurrentBranch()).toBe('newbranch'); + expect(parser.yy.getBranches()['newbranch']).toEqual(parser.yy.getBranches()['master']); + expect(parser.yy.getHead().id).toEqual(parser.yy.getBranches()['master']); - parser.yy.prettyPrint() - }) -}) + parser.yy.prettyPrint(); + }); +}); diff --git a/src/diagrams/git/gitGraphRenderer.js b/src/diagrams/git/gitGraphRenderer.js index 00f56ed1a..9a66141a0 100644 --- a/src/diagrams/git/gitGraphRenderer.js +++ b/src/diagrams/git/gitGraphRenderer.js @@ -1,13 +1,13 @@ -import * as d3 from 'd3' -import _ from 'lodash' +import * as d3 from 'd3'; +import _ from 'lodash'; -import db from './gitGraphAst' -import gitGraphParser from './parser/gitGraph' -import { logger } from '../../logger' -import { interpolateToCurve } from '../../utils' +import db from './gitGraphAst'; +import gitGraphParser from './parser/gitGraph'; +import { logger } from '../../logger'; +import { interpolateToCurve } from '../../utils'; -let allCommitsDict = {} -let branchNum +let allCommitsDict = {}; +let branchNum; let config = { nodeSpacing: 150, nodeFillColor: 'yellow', @@ -25,13 +25,13 @@ let config = { x: -25, y: 0 } -} -let apiConfig = {} -export const setConf = function (c) { - apiConfig = c -} +}; +let apiConfig = {}; +export const setConf = function(c) { + apiConfig = c; +}; -function svgCreateDefs (svg) { +function svgCreateDefs(svg) { svg .append('defs') .append('g') @@ -39,8 +39,9 @@ function svgCreateDefs (svg) { .append('circle') .attr('r', config.nodeRadius) .attr('cx', 0) - .attr('cy', 0) - svg.select('#def-commit') + .attr('cy', 0); + svg + .select('#def-commit') .append('foreignObject') .attr('width', config.nodeLabel.width) .attr('height', config.nodeLabel.height) @@ -49,239 +50,293 @@ function svgCreateDefs (svg) { .attr('class', 'node-label') .attr('requiredFeatures', 'http://www.w3.org/TR/SVG11/feature#Extensibility') .append('p') - .html('') + .html(''); } -function svgDrawLine (svg, points, colorIdx, interpolate) { - const curve = interpolateToCurve(interpolate, d3.curveBasis) - const color = config.branchColors[colorIdx % config.branchColors.length] - const lineGen = d3.line() - .x(function (d) { - return Math.round(d.x) +function svgDrawLine(svg, points, colorIdx, interpolate) { + const curve = interpolateToCurve(interpolate, d3.curveBasis); + const color = config.branchColors[colorIdx % config.branchColors.length]; + const lineGen = d3 + .line() + .x(function(d) { + return Math.round(d.x); }) - .y(function (d) { - return Math.round(d.y) + .y(function(d) { + return Math.round(d.y); }) - .curve(curve) + .curve(curve); svg .append('svg:path') .attr('d', lineGen(points)) .style('stroke', color) .style('stroke-width', config.lineStrokeWidth) - .style('fill', 'none') + .style('fill', 'none'); } // Pass in the element and its pre-transform coords -function getElementCoords (element, coords) { - coords = coords || element.node().getBBox() - const ctm = element.node().getCTM() - const xn = ctm.e + coords.x * ctm.a - const yn = ctm.f + coords.y * ctm.d +function getElementCoords(element, coords) { + coords = coords || element.node().getBBox(); + const ctm = element.node().getCTM(); + const xn = ctm.e + coords.x * ctm.a; + const yn = ctm.f + coords.y * ctm.d; return { left: xn, top: yn, width: coords.width, height: coords.height - } + }; } -function svgDrawLineForCommits (svg, fromId, toId, direction, color) { - logger.debug('svgDrawLineForCommits: ', fromId, toId) - const fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle')) - const toBbox = getElementCoords(svg.select('#node-' + toId + ' circle')) +function svgDrawLineForCommits(svg, fromId, toId, direction, color) { + logger.debug('svgDrawLineForCommits: ', fromId, toId); + const fromBbox = getElementCoords(svg.select('#node-' + fromId + ' circle')); + const toBbox = getElementCoords(svg.select('#node-' + toId + ' circle')); switch (direction) { case 'LR': // (toBbox) // +-------- // + (fromBbox) if (fromBbox.left - toBbox.left > config.nodeSpacing) { - const lineStart = { x: fromBbox.left - config.nodeSpacing, y: toBbox.top + toBbox.height / 2 } - const lineEnd = { x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height / 2 } - svgDrawLine(svg, [lineStart, lineEnd], color, 'linear') - svgDrawLine(svg, [ - { x: fromBbox.left, y: fromBbox.top + fromBbox.height / 2 }, - { x: fromBbox.left - config.nodeSpacing / 2, y: fromBbox.top + fromBbox.height / 2 }, - { x: fromBbox.left - config.nodeSpacing / 2, y: lineStart.y }, - lineStart], color) + const lineStart = { + x: fromBbox.left - config.nodeSpacing, + y: toBbox.top + toBbox.height / 2 + }; + const lineEnd = { x: toBbox.left + toBbox.width, y: toBbox.top + toBbox.height / 2 }; + svgDrawLine(svg, [lineStart, lineEnd], color, 'linear'); + svgDrawLine( + svg, + [ + { x: fromBbox.left, y: fromBbox.top + fromBbox.height / 2 }, + { x: fromBbox.left - config.nodeSpacing / 2, y: fromBbox.top + fromBbox.height / 2 }, + { x: fromBbox.left - config.nodeSpacing / 2, y: lineStart.y }, + lineStart + ], + color + ); } else { - svgDrawLine(svg, [{ - 'x': fromBbox.left, - 'y': fromBbox.top + fromBbox.height / 2 - }, { - 'x': fromBbox.left - config.nodeSpacing / 2, - 'y': fromBbox.top + fromBbox.height / 2 - }, { - 'x': fromBbox.left - config.nodeSpacing / 2, - 'y': toBbox.top + toBbox.height / 2 - }, { - 'x': toBbox.left + toBbox.width, - 'y': toBbox.top + toBbox.height / 2 - }], color) + svgDrawLine( + svg, + [ + { + x: fromBbox.left, + y: fromBbox.top + fromBbox.height / 2 + }, + { + x: fromBbox.left - config.nodeSpacing / 2, + y: fromBbox.top + fromBbox.height / 2 + }, + { + x: fromBbox.left - config.nodeSpacing / 2, + y: toBbox.top + toBbox.height / 2 + }, + { + x: toBbox.left + toBbox.width, + y: toBbox.top + toBbox.height / 2 + } + ], + color + ); } - break + break; case 'BT': // + (fromBbox) // | // | // + (toBbox) if (toBbox.top - fromBbox.top > config.nodeSpacing) { - const lineStart = { x: toBbox.left + toBbox.width / 2, y: fromBbox.top + fromBbox.height + config.nodeSpacing } - const lineEnd = { x: toBbox.left + toBbox.width / 2, y: toBbox.top } - svgDrawLine(svg, [lineStart, lineEnd], color, 'linear') - svgDrawLine(svg, [ - { x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height }, - { x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height + config.nodeSpacing / 2 }, - { x: toBbox.left + toBbox.width / 2, y: lineStart.y - config.nodeSpacing / 2 }, - lineStart], color) + const lineStart = { + x: toBbox.left + toBbox.width / 2, + y: fromBbox.top + fromBbox.height + config.nodeSpacing + }; + const lineEnd = { x: toBbox.left + toBbox.width / 2, y: toBbox.top }; + svgDrawLine(svg, [lineStart, lineEnd], color, 'linear'); + svgDrawLine( + svg, + [ + { x: fromBbox.left + fromBbox.width / 2, y: fromBbox.top + fromBbox.height }, + { + x: fromBbox.left + fromBbox.width / 2, + y: fromBbox.top + fromBbox.height + config.nodeSpacing / 2 + }, + { x: toBbox.left + toBbox.width / 2, y: lineStart.y - config.nodeSpacing / 2 }, + lineStart + ], + color + ); } else { - svgDrawLine(svg, [{ - 'x': fromBbox.left + fromBbox.width / 2, - 'y': fromBbox.top + fromBbox.height - }, { - 'x': fromBbox.left + fromBbox.width / 2, - 'y': fromBbox.top + config.nodeSpacing / 2 - }, { - 'x': toBbox.left + toBbox.width / 2, - 'y': toBbox.top - config.nodeSpacing / 2 - }, { - 'x': toBbox.left + toBbox.width / 2, - 'y': toBbox.top - }], color) + svgDrawLine( + svg, + [ + { + x: fromBbox.left + fromBbox.width / 2, + y: fromBbox.top + fromBbox.height + }, + { + x: fromBbox.left + fromBbox.width / 2, + y: fromBbox.top + config.nodeSpacing / 2 + }, + { + x: toBbox.left + toBbox.width / 2, + y: toBbox.top - config.nodeSpacing / 2 + }, + { + x: toBbox.left + toBbox.width / 2, + y: toBbox.top + } + ], + color + ); } - break + break; } } -function cloneNode (svg, selector) { - return svg.select(selector).node().cloneNode(true) +function cloneNode(svg, selector) { + return svg + .select(selector) + .node() + .cloneNode(true); } -function renderCommitHistory (svg, commitid, branches, direction) { - let commit - const numCommits = Object.keys(allCommitsDict).length +function renderCommitHistory(svg, commitid, branches, direction) { + let commit; + const numCommits = Object.keys(allCommitsDict).length; if (typeof commitid === 'string') { do { - commit = allCommitsDict[commitid] - logger.debug('in renderCommitHistory', commit.id, commit.seq) + commit = allCommitsDict[commitid]; + logger.debug('in renderCommitHistory', commit.id, commit.seq); if (svg.select('#node-' + commitid).size() > 0) { - return + return; } svg - .append(function () { - return cloneNode(svg, '#def-commit') + .append(function() { + return cloneNode(svg, '#def-commit'); }) .attr('class', 'commit') - .attr('id', function () { - return 'node-' + commit.id + .attr('id', function() { + return 'node-' + commit.id; }) - .attr('transform', function () { + .attr('transform', function() { switch (direction) { case 'LR': - return 'translate(' + (commit.seq * config.nodeSpacing + config.leftMargin) + ', ' + - (branchNum * config.branchOffset) + ')' + return ( + 'translate(' + + (commit.seq * config.nodeSpacing + config.leftMargin) + + ', ' + + branchNum * config.branchOffset + + ')' + ); case 'BT': - return 'translate(' + (branchNum * config.branchOffset + config.leftMargin) + ', ' + - ((numCommits - commit.seq) * config.nodeSpacing) + ')' + return ( + 'translate(' + + (branchNum * config.branchOffset + config.leftMargin) + + ', ' + + (numCommits - commit.seq) * config.nodeSpacing + + ')' + ); } }) .attr('fill', config.nodeFillColor) .attr('stroke', config.nodeStrokeColor) - .attr('stroke-width', config.nodeStrokeWidth) + .attr('stroke-width', config.nodeStrokeWidth); - let branch + let branch; for (let branchName in branches) { if (branches[branchName].commit === commit) { - branch = branches[branchName] - break + branch = branches[branchName]; + break; } } if (branch) { - logger.debug('found branch ', branch.name) - svg.select('#node-' + commit.id + ' p') + logger.debug('found branch ', branch.name); + svg + .select('#node-' + commit.id + ' p') .append('xhtml:span') .attr('class', 'branch-label') - .text(branch.name + ', ') + .text(branch.name + ', '); } - svg.select('#node-' + commit.id + ' p') + svg + .select('#node-' + commit.id + ' p') .append('xhtml:span') .attr('class', 'commit-id') - .text(commit.id) + .text(commit.id); if (commit.message !== '' && direction === 'BT') { - svg.select('#node-' + commit.id + ' p') + svg + .select('#node-' + commit.id + ' p') .append('xhtml:span') .attr('class', 'commit-msg') - .text(', ' + commit.message) + .text(', ' + commit.message); } - commitid = commit.parent - } while (commitid && allCommitsDict[commitid]) + commitid = commit.parent; + } while (commitid && allCommitsDict[commitid]); } if (Array.isArray(commitid)) { - logger.debug('found merge commmit', commitid) - renderCommitHistory(svg, commitid[0], branches, direction) - branchNum++ - renderCommitHistory(svg, commitid[1], branches, direction) - branchNum-- + logger.debug('found merge commmit', commitid); + renderCommitHistory(svg, commitid[0], branches, direction); + branchNum++; + renderCommitHistory(svg, commitid[1], branches, direction); + branchNum--; } } -function renderLines (svg, commit, direction, branchColor) { - branchColor = branchColor || 0 +function renderLines(svg, commit, direction, branchColor) { + branchColor = branchColor || 0; while (commit.seq > 0 && !commit.lineDrawn) { if (typeof commit.parent === 'string') { - svgDrawLineForCommits(svg, commit.id, commit.parent, direction, branchColor) - commit.lineDrawn = true - commit = allCommitsDict[commit.parent] + svgDrawLineForCommits(svg, commit.id, commit.parent, direction, branchColor); + commit.lineDrawn = true; + commit = allCommitsDict[commit.parent]; } else if (Array.isArray(commit.parent)) { - svgDrawLineForCommits(svg, commit.id, commit.parent[0], direction, branchColor) - svgDrawLineForCommits(svg, commit.id, commit.parent[1], direction, branchColor + 1) - renderLines(svg, allCommitsDict[commit.parent[1]], direction, branchColor + 1) - commit.lineDrawn = true - commit = allCommitsDict[commit.parent[0]] + svgDrawLineForCommits(svg, commit.id, commit.parent[0], direction, branchColor); + svgDrawLineForCommits(svg, commit.id, commit.parent[1], direction, branchColor + 1); + renderLines(svg, allCommitsDict[commit.parent[1]], direction, branchColor + 1); + commit.lineDrawn = true; + commit = allCommitsDict[commit.parent[0]]; } } } -export const draw = function (txt, id, ver) { +export const draw = function(txt, id, ver) { try { - const parser = gitGraphParser.parser - parser.yy = db + const parser = gitGraphParser.parser; + parser.yy = db; - logger.debug('in gitgraph renderer', txt, id, ver) + logger.debug('in gitgraph renderer', txt, id, ver); // Parse the graph definition - parser.parse(txt + '\n') + parser.parse(txt + '\n'); - config = _.assign(config, apiConfig, db.getOptions()) - logger.debug('effective options', config) - const direction = db.getDirection() - allCommitsDict = db.getCommits() - const branches = db.getBranchesAsObjArray() + config = _.assign(config, apiConfig, db.getOptions()); + logger.debug('effective options', config); + const direction = db.getDirection(); + allCommitsDict = db.getCommits(); + const branches = db.getBranchesAsObjArray(); if (direction === 'BT') { - config.nodeLabel.x = branches.length * config.branchOffset - config.nodeLabel.width = '100%' - config.nodeLabel.y = -1 * 2 * config.nodeRadius + config.nodeLabel.x = branches.length * config.branchOffset; + config.nodeLabel.width = '100%'; + config.nodeLabel.y = -1 * 2 * config.nodeRadius; } - const svg = d3.select(`[id="${id}"]`) - svgCreateDefs(svg) - branchNum = 1 + const svg = d3.select(`[id="${id}"]`); + svgCreateDefs(svg); + branchNum = 1; for (let branch in branches) { - const v = branches[branch] - renderCommitHistory(svg, v.commit.id, branches, direction) - renderLines(svg, v.commit, direction) - branchNum++ + const v = branches[branch]; + renderCommitHistory(svg, v.commit.id, branches, direction); + renderLines(svg, v.commit, direction); + branchNum++; } - svg.attr('height', function () { - if (direction === 'BT') return Object.keys(allCommitsDict).length * config.nodeSpacing - return (branches.length + 1) * config.branchOffset - }) + svg.attr('height', function() { + if (direction === 'BT') return Object.keys(allCommitsDict).length * config.nodeSpacing; + return (branches.length + 1) * config.branchOffset; + }); } catch (e) { - logger.error('Error while rendering gitgraph') - logger.error(e.message) + logger.error('Error while rendering gitgraph'); + logger.error(e.message); } -} +}; export default { setConf, draw -} +}; From cf05a8d8fa06e64309af4acf599af55b29eff792 Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:57:36 -0700 Subject: [PATCH 09/13] #931 Updating code to align witn new code standard --- src/diagrams/gantt/ganttDb.js | 634 ++++++++++++------------ src/diagrams/gantt/ganttDb.spec.js | 297 +++++------ src/diagrams/gantt/ganttRenderer.js | 375 +++++++------- src/diagrams/gantt/parser/gantt.spec.js | 126 ++--- 4 files changed, 746 insertions(+), 686 deletions(-) diff --git a/src/diagrams/gantt/ganttDb.js b/src/diagrams/gantt/ganttDb.js index 46ba09e04..9eb2b8c38 100644 --- a/src/diagrams/gantt/ganttDb.js +++ b/src/diagrams/gantt/ganttDb.js @@ -1,217 +1,214 @@ -import moment from 'moment-mini' -import { sanitizeUrl } from '@braintree/sanitize-url' -import { logger } from '../../logger' -import { getConfig } from '../../config' +import moment from 'moment-mini'; +import { sanitizeUrl } from '@braintree/sanitize-url'; +import { logger } from '../../logger'; +import { getConfig } from '../../config'; -const config = getConfig() -let dateFormat = '' -let axisFormat = '' -let excludes = [] -let title = '' -let sections = [] -let tasks = [] -let currentSection = '' -const tags = ['active', 'done', 'crit', 'milestone'] -let funs = [] -let inclusiveEndDates = false +const config = getConfig(); +let dateFormat = ''; +let axisFormat = ''; +let excludes = []; +let title = ''; +let sections = []; +let tasks = []; +let currentSection = ''; +const tags = ['active', 'done', 'crit', 'milestone']; +let funs = []; +let inclusiveEndDates = false; -export const clear = function () { - sections = [] - tasks = [] - currentSection = '' - funs = [] - title = '' - taskCnt = 0 - lastTask = undefined - lastTaskID = undefined - rawTasks = [] - dateFormat = '' - axisFormat = '' - excludes = [] - inclusiveEndDates = false -} +export const clear = function() { + sections = []; + tasks = []; + currentSection = ''; + funs = []; + title = ''; + taskCnt = 0; + lastTask = undefined; + lastTaskID = undefined; + rawTasks = []; + dateFormat = ''; + axisFormat = ''; + excludes = []; + inclusiveEndDates = false; +}; -export const setAxisFormat = function (txt) { - axisFormat = txt -} +export const setAxisFormat = function(txt) { + axisFormat = txt; +}; -export const getAxisFormat = function () { - return axisFormat -} +export const getAxisFormat = function() { + return axisFormat; +}; -export const setDateFormat = function (txt) { - dateFormat = txt -} +export const setDateFormat = function(txt) { + dateFormat = txt; +}; -export const enableInclusiveEndDates = function () { - inclusiveEndDates = true -} +export const enableInclusiveEndDates = function() { + inclusiveEndDates = true; +}; -export const endDatesAreInclusive = function () { - return inclusiveEndDates -} +export const endDatesAreInclusive = function() { + return inclusiveEndDates; +}; -export const getDateFormat = function () { - return dateFormat -} +export const getDateFormat = function() { + return dateFormat; +}; -export const setExcludes = function (txt) { - excludes = txt.toLowerCase().split(/[\s,]+/) -} +export const setExcludes = function(txt) { + excludes = txt.toLowerCase().split(/[\s,]+/); +}; -export const getExcludes = function () { - return excludes -} +export const getExcludes = function() { + return excludes; +}; -export const setTitle = function (txt) { - title = txt -} +export const setTitle = function(txt) { + title = txt; +}; -export const getTitle = function () { - return title -} +export const getTitle = function() { + return title; +}; -export const addSection = function (txt) { - currentSection = txt - sections.push(txt) -} +export const addSection = function(txt) { + currentSection = txt; + sections.push(txt); +}; -export const getSections = function () { - return sections -} +export const getSections = function() { + return sections; +}; -export const getTasks = function () { - let allItemsPricessed = compileTasks() - const maxDepth = 10 - let iterationCount = 0 - while (!allItemsPricessed && (iterationCount < maxDepth)) { - allItemsPricessed = compileTasks() - iterationCount++ +export const getTasks = function() { + let allItemsPricessed = compileTasks(); + const maxDepth = 10; + let iterationCount = 0; + while (!allItemsPricessed && iterationCount < maxDepth) { + allItemsPricessed = compileTasks(); + iterationCount++; } - tasks = rawTasks + tasks = rawTasks; - return tasks -} + return tasks; +}; -const isInvalidDate = function (date, dateFormat, excludes) { +const isInvalidDate = function(date, dateFormat, excludes) { if (date.isoWeekday() >= 6 && excludes.indexOf('weekends') >= 0) { - return true + return true; } if (excludes.indexOf(date.format('dddd').toLowerCase()) >= 0) { - return true + return true; } - return excludes.indexOf(date.format(dateFormat.trim())) >= 0 -} + return excludes.indexOf(date.format(dateFormat.trim())) >= 0; +}; -const checkTaskDates = function (task, dateFormat, excludes) { - if (!excludes.length || task.manualEndTime) return - let startTime = moment(task.startTime, dateFormat, true) - startTime.add(1, 'd') - let endTime = moment(task.endTime, dateFormat, true) - let renderEndTime = fixTaskDates(startTime, endTime, dateFormat, excludes) - task.endTime = endTime.toDate() - task.renderEndTime = renderEndTime -} +const checkTaskDates = function(task, dateFormat, excludes) { + if (!excludes.length || task.manualEndTime) return; + let startTime = moment(task.startTime, dateFormat, true); + startTime.add(1, 'd'); + let endTime = moment(task.endTime, dateFormat, true); + let renderEndTime = fixTaskDates(startTime, endTime, dateFormat, excludes); + task.endTime = endTime.toDate(); + task.renderEndTime = renderEndTime; +}; -const fixTaskDates = function (startTime, endTime, dateFormat, excludes) { - let invalid = false - let renderEndTime = null +const fixTaskDates = function(startTime, endTime, dateFormat, excludes) { + let invalid = false; + let renderEndTime = null; while (startTime.date() <= endTime.date()) { if (!invalid) { - renderEndTime = endTime.toDate() + renderEndTime = endTime.toDate(); } - invalid = isInvalidDate(startTime, dateFormat, excludes) + invalid = isInvalidDate(startTime, dateFormat, excludes); if (invalid) { - endTime.add(1, 'd') + endTime.add(1, 'd'); } - startTime.add(1, 'd') + startTime.add(1, 'd'); } - return renderEndTime -} + return renderEndTime; +}; -const getStartDate = function (prevTime, dateFormat, str) { - str = str.trim() +const getStartDate = function(prevTime, dateFormat, str) { + str = str.trim(); // Test for after - const re = /^after\s+([\d\w-]+)/ - const afterStatement = re.exec(str.trim()) + const re = /^after\s+([\d\w-]+)/; + const afterStatement = re.exec(str.trim()); if (afterStatement !== null) { - const task = findTaskById(afterStatement[1]) + const task = findTaskById(afterStatement[1]); if (typeof task === 'undefined') { - const dt = new Date() - dt.setHours(0, 0, 0, 0) - return dt + const dt = new Date(); + dt.setHours(0, 0, 0, 0); + return dt; } - return task.endTime + return task.endTime; } // Check for actual date set - let mDate = moment(str, dateFormat.trim(), true) + let mDate = moment(str, dateFormat.trim(), true); if (mDate.isValid()) { - return mDate.toDate() + return mDate.toDate(); } else { - logger.debug('Invalid date:' + str) - logger.debug('With date format:' + dateFormat.trim()) + logger.debug('Invalid date:' + str); + logger.debug('With date format:' + dateFormat.trim()); } // Default date - now - return new Date() -} + return new Date(); +}; -const durationToDate = function (durationStatement, relativeTime) { +const durationToDate = function(durationStatement, relativeTime) { if (durationStatement !== null) { switch (durationStatement[2]) { case 's': - relativeTime.add(durationStatement[1], 'seconds') - break + relativeTime.add(durationStatement[1], 'seconds'); + break; case 'm': - relativeTime.add(durationStatement[1], 'minutes') - break + relativeTime.add(durationStatement[1], 'minutes'); + break; case 'h': - relativeTime.add(durationStatement[1], 'hours') - break + relativeTime.add(durationStatement[1], 'hours'); + break; case 'd': - relativeTime.add(durationStatement[1], 'days') - break + relativeTime.add(durationStatement[1], 'days'); + break; case 'w': - relativeTime.add(durationStatement[1], 'weeks') - break + relativeTime.add(durationStatement[1], 'weeks'); + break; } } // Default date - now - return relativeTime.toDate() -} + return relativeTime.toDate(); +}; -const getEndDate = function (prevTime, dateFormat, str, inclusive) { - inclusive = inclusive || false - str = str.trim() +const getEndDate = function(prevTime, dateFormat, str, inclusive) { + inclusive = inclusive || false; + str = str.trim(); // Check for actual date - let mDate = moment(str, dateFormat.trim(), true) + let mDate = moment(str, dateFormat.trim(), true); if (mDate.isValid()) { if (inclusive) { - mDate.add(1, 'd') + mDate.add(1, 'd'); } - return mDate.toDate() + return mDate.toDate(); } - return durationToDate( - /^([\d]+)([wdhms])/.exec(str.trim()), - moment(prevTime) - ) -} + return durationToDate(/^([\d]+)([wdhms])/.exec(str.trim()), moment(prevTime)); +}; -let taskCnt = 0 -const parseId = function (idStr) { +let taskCnt = 0; +const parseId = function(idStr) { if (typeof idStr === 'undefined') { - taskCnt = taskCnt + 1 - return 'task' + taskCnt + taskCnt = taskCnt + 1; + return 'task' + taskCnt; } - return idStr -} + return idStr; +}; // id, startDate, endDate // id, startDate, length // id, after x, endDate @@ -223,116 +220,116 @@ const parseId = function (idStr) { // endDate // length -const compileData = function (prevTask, dataStr) { - let ds +const compileData = function(prevTask, dataStr) { + let ds; if (dataStr.substr(0, 1) === ':') { - ds = dataStr.substr(1, dataStr.length) + ds = dataStr.substr(1, dataStr.length); } else { - ds = dataStr + ds = dataStr; } - const data = ds.split(',') + const data = ds.split(','); - const task = {} + const task = {}; // Get tags like active, done, crit and milestone - getTaskTags(data, task, tags) + getTaskTags(data, task, tags); for (let i = 0; i < data.length; i++) { - data[i] = data[i].trim() + data[i] = data[i].trim(); } - let endTimeData = '' + let endTimeData = ''; switch (data.length) { case 1: - task.id = parseId() - task.startTime = prevTask.endTime - endTimeData = data[0] - break + task.id = parseId(); + task.startTime = prevTask.endTime; + endTimeData = data[0]; + break; case 2: - task.id = parseId() - task.startTime = getStartDate(undefined, dateFormat, data[0]) - endTimeData = data[1] - break + task.id = parseId(); + task.startTime = getStartDate(undefined, dateFormat, data[0]); + endTimeData = data[1]; + break; case 3: - task.id = parseId(data[0]) - task.startTime = getStartDate(undefined, dateFormat, data[1]) - endTimeData = data[2] - break + task.id = parseId(data[0]); + task.startTime = getStartDate(undefined, dateFormat, data[1]); + endTimeData = data[2]; + break; default: } if (endTimeData) { - task.endTime = getEndDate(task.startTime, dateFormat, endTimeData, inclusiveEndDates) - task.manualEndTime = moment(endTimeData, 'YYYY-MM-DD', true).isValid() - checkTaskDates(task, dateFormat, excludes) + task.endTime = getEndDate(task.startTime, dateFormat, endTimeData, inclusiveEndDates); + task.manualEndTime = moment(endTimeData, 'YYYY-MM-DD', true).isValid(); + checkTaskDates(task, dateFormat, excludes); } - return task -} + return task; +}; -const parseData = function (prevTaskId, dataStr) { - let ds +const parseData = function(prevTaskId, dataStr) { + let ds; if (dataStr.substr(0, 1) === ':') { - ds = dataStr.substr(1, dataStr.length) + ds = dataStr.substr(1, dataStr.length); } else { - ds = dataStr + ds = dataStr; } - const data = ds.split(',') + const data = ds.split(','); - const task = {} + const task = {}; // Get tags like active, done, crit and milestone - getTaskTags(data, task, tags) + getTaskTags(data, task, tags); for (let i = 0; i < data.length; i++) { - data[i] = data[i].trim() + data[i] = data[i].trim(); } switch (data.length) { case 1: - task.id = parseId() + task.id = parseId(); task.startTime = { type: 'prevTaskEnd', id: prevTaskId - } + }; task.endTime = { data: data[0] - } - break + }; + break; case 2: - task.id = parseId() + task.id = parseId(); task.startTime = { type: 'getStartDate', startData: data[0] - } + }; task.endTime = { data: data[1] - } - break + }; + break; case 3: - task.id = parseId(data[0]) + task.id = parseId(data[0]); task.startTime = { type: 'getStartDate', startData: data[1] - } + }; task.endTime = { data: data[2] - } - break + }; + break; default: } - return task -} + return task; +}; -let lastTask -let lastTaskID -let rawTasks = [] -const taskDb = {} -export const addTask = function (descr, data) { +let lastTask; +let lastTaskID; +let rawTasks = []; +const taskDb = {}; +export const addTask = function(descr, data) { const rawTask = { section: currentSection, type: currentSection, @@ -342,174 +339,187 @@ export const addTask = function (descr, data) { raw: { data: data }, task: descr, classes: [] - } - const taskInfo = parseData(lastTaskID, data) - rawTask.raw.startTime = taskInfo.startTime - rawTask.raw.endTime = taskInfo.endTime - rawTask.id = taskInfo.id - rawTask.prevTaskId = lastTaskID - rawTask.active = taskInfo.active - rawTask.done = taskInfo.done - rawTask.crit = taskInfo.crit - rawTask.milestone = taskInfo.milestone + }; + const taskInfo = parseData(lastTaskID, data); + rawTask.raw.startTime = taskInfo.startTime; + rawTask.raw.endTime = taskInfo.endTime; + rawTask.id = taskInfo.id; + rawTask.prevTaskId = lastTaskID; + rawTask.active = taskInfo.active; + rawTask.done = taskInfo.done; + rawTask.crit = taskInfo.crit; + rawTask.milestone = taskInfo.milestone; - const pos = rawTasks.push(rawTask) + const pos = rawTasks.push(rawTask); - lastTaskID = rawTask.id + lastTaskID = rawTask.id; // Store cross ref - taskDb[rawTask.id] = pos - 1 -} + taskDb[rawTask.id] = pos - 1; +}; -export const findTaskById = function (id) { - const pos = taskDb[id] - return rawTasks[pos] -} +export const findTaskById = function(id) { + const pos = taskDb[id]; + return rawTasks[pos]; +}; -export const addTaskOrg = function (descr, data) { +export const addTaskOrg = function(descr, data) { const newTask = { section: currentSection, type: currentSection, description: descr, task: descr, classes: [] - } - const taskInfo = compileData(lastTask, data) - newTask.startTime = taskInfo.startTime - newTask.endTime = taskInfo.endTime - newTask.id = taskInfo.id - newTask.active = taskInfo.active - newTask.done = taskInfo.done - newTask.crit = taskInfo.crit - newTask.milestone = taskInfo.milestone - lastTask = newTask - tasks.push(newTask) -} + }; + const taskInfo = compileData(lastTask, data); + newTask.startTime = taskInfo.startTime; + newTask.endTime = taskInfo.endTime; + newTask.id = taskInfo.id; + newTask.active = taskInfo.active; + newTask.done = taskInfo.done; + newTask.crit = taskInfo.crit; + newTask.milestone = taskInfo.milestone; + lastTask = newTask; + tasks.push(newTask); +}; -const compileTasks = function () { - const compileTask = function (pos) { - const task = rawTasks[pos] - let startTime = '' +const compileTasks = function() { + const compileTask = function(pos) { + const task = rawTasks[pos]; + let startTime = ''; switch (rawTasks[pos].raw.startTime.type) { case 'prevTaskEnd': - const prevTask = findTaskById(task.prevTaskId) - task.startTime = prevTask.endTime - break + const prevTask = findTaskById(task.prevTaskId); + task.startTime = prevTask.endTime; + break; case 'getStartDate': - startTime = getStartDate(undefined, dateFormat, rawTasks[pos].raw.startTime.startData) + startTime = getStartDate(undefined, dateFormat, rawTasks[pos].raw.startTime.startData); if (startTime) { - rawTasks[pos].startTime = startTime + rawTasks[pos].startTime = startTime; } - break + break; } if (rawTasks[pos].startTime) { - rawTasks[pos].endTime = getEndDate(rawTasks[pos].startTime, dateFormat, rawTasks[pos].raw.endTime.data, inclusiveEndDates) + rawTasks[pos].endTime = getEndDate( + rawTasks[pos].startTime, + dateFormat, + rawTasks[pos].raw.endTime.data, + inclusiveEndDates + ); if (rawTasks[pos].endTime) { - rawTasks[pos].processed = true - rawTasks[pos].manualEndTime = moment(rawTasks[pos].raw.endTime.data, 'YYYY-MM-DD', true).isValid() - checkTaskDates(rawTasks[pos], dateFormat, excludes) + rawTasks[pos].processed = true; + rawTasks[pos].manualEndTime = moment( + rawTasks[pos].raw.endTime.data, + 'YYYY-MM-DD', + true + ).isValid(); + checkTaskDates(rawTasks[pos], dateFormat, excludes); } } - return rawTasks[pos].processed - } + return rawTasks[pos].processed; + }; - let allProcessed = true + let allProcessed = true; for (let i = 0; i < rawTasks.length; i++) { - compileTask(i) + compileTask(i); - allProcessed = allProcessed && rawTasks[i].processed + allProcessed = allProcessed && rawTasks[i].processed; } - return allProcessed -} + return allProcessed; +}; /** * Called by parser when a link is found. Adds the URL to the vertex data. * @param ids Comma separated list of ids * @param linkStr URL to create a link for */ -export const setLink = function (ids, _linkStr) { - let linkStr = _linkStr +export const setLink = function(ids, _linkStr) { + let linkStr = _linkStr; if (config.securityLevel !== 'loose') { - linkStr = sanitizeUrl(_linkStr) + linkStr = sanitizeUrl(_linkStr); } - ids.split(',').forEach(function (id) { - let rawTask = findTaskById(id) + ids.split(',').forEach(function(id) { + let rawTask = findTaskById(id); if (typeof rawTask !== 'undefined') { - pushFun(id, () => { window.open(linkStr, '_self') }) + pushFun(id, () => { + window.open(linkStr, '_self'); + }); } - }) - setClass(ids, 'clickable') -} + }); + setClass(ids, 'clickable'); +}; /** * Called by parser when a special node is found, e.g. a clickable element. * @param ids Comma separated list of ids * @param className Class to add */ -export const setClass = function (ids, className) { - ids.split(',').forEach(function (id) { - let rawTask = findTaskById(id) +export const setClass = function(ids, className) { + ids.split(',').forEach(function(id) { + let rawTask = findTaskById(id); if (typeof rawTask !== 'undefined') { - rawTask.classes.push(className) + rawTask.classes.push(className); } - }) -} + }); +}; -const setClickFun = function (id, functionName, functionArgs) { +const setClickFun = function(id, functionName, functionArgs) { if (config.securityLevel !== 'loose') { - return + return; } if (typeof functionName === 'undefined') { - return + return; } - let argList = [] + let argList = []; if (typeof functionArgs === 'string') { /* Splits functionArgs by ',', ignoring all ',' in double quoted strings */ - argList = functionArgs.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/) + argList = functionArgs.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/); for (let i = 0; i < argList.length; i++) { - let item = argList[i].trim() + let item = argList[i].trim(); /* Removes all double quotes at the start and end of an argument */ /* This preserves all starting and ending whitespace inside */ if (item.charAt(0) === '"' && item.charAt(item.length - 1) === '"') { - item = item.substr(1, item.length - 2) + item = item.substr(1, item.length - 2); } - argList[i] = item + argList[i] = item; } } - let rawTask = findTaskById(id) + let rawTask = findTaskById(id); if (typeof rawTask !== 'undefined') { - pushFun(id, () => { window[functionName](...argList) }) + pushFun(id, () => { + window[functionName](...argList); + }); } -} +}; /** * The callbackFunction is executed in a click event bound to the task with the specified id or the task's assigned text * @param id The task's id * @param callbackFunction A function to be executed when clicked on the task or the task's text */ -const pushFun = function (id, callbackFunction) { - funs.push(function (element) { +const pushFun = function(id, callbackFunction) { + funs.push(function(element) { // const elem = d3.select(element).select(`[id="${id}"]`) - const elem = document.querySelector(`[id="${id}"]`) + const elem = document.querySelector(`[id="${id}"]`); if (elem !== null) { - elem.addEventListener('click', function () { - callbackFunction() - }) + elem.addEventListener('click', function() { + callbackFunction(); + }); } - }) - funs.push(function (element) { + }); + funs.push(function(element) { // const elem = d3.select(element).select(`[id="${id}-text"]`) - const elem = document.querySelector(`[id="${id}-text"]`) + const elem = document.querySelector(`[id="${id}-text"]`); if (elem !== null) { - elem.addEventListener('click', function () { - callbackFunction() - }) + elem.addEventListener('click', function() { + callbackFunction(); + }); } - }) -} + }); +}; /** * Called by parser when a click definition is found. Registers an event handler. @@ -517,22 +527,22 @@ const pushFun = function (id, callbackFunction) { * @param functionName Function to be called on click * @param functionArgs Function args the function should be called with */ -export const setClickEvent = function (ids, functionName, functionArgs) { - ids.split(',').forEach(function (id) { - setClickFun(id, functionName, functionArgs) - }) - setClass(ids, 'clickable') -} +export const setClickEvent = function(ids, functionName, functionArgs) { + ids.split(',').forEach(function(id) { + setClickFun(id, functionName, functionArgs); + }); + setClass(ids, 'clickable'); +}; /** * Binds all functions previously added to fun (specified through click) to the element * @param element */ -export const bindFunctions = function (element) { - funs.forEach(function (fun) { - fun(element) - }) -} +export const bindFunctions = function(element) { + funs.forEach(function(fun) { + fun(element); + }); +}; export default { clear, @@ -556,20 +566,20 @@ export default { setLink, bindFunctions, durationToDate -} +}; -function getTaskTags (data, task, tags) { - let matchFound = true +function getTaskTags(data, task, tags) { + let matchFound = true; while (matchFound) { - matchFound = false - tags.forEach(function (t) { - const pattern = '^\\s*' + t + '\\s*$' - const regex = new RegExp(pattern) + matchFound = false; + tags.forEach(function(t) { + const pattern = '^\\s*' + t + '\\s*$'; + const regex = new RegExp(pattern); if (data[0].match(regex)) { - task[t] = true - data.shift(1) - matchFound = true + task[t] = true; + data.shift(1); + matchFound = true; } - }) + }); } } diff --git a/src/diagrams/gantt/ganttDb.spec.js b/src/diagrams/gantt/ganttDb.spec.js index 1dad71ad6..433e3a495 100644 --- a/src/diagrams/gantt/ganttDb.spec.js +++ b/src/diagrams/gantt/ganttDb.spec.js @@ -1,32 +1,32 @@ /* eslint-env jasmine */ -import moment from 'moment-mini' -import ganttDb from './ganttDb' +import moment from 'moment-mini'; +import ganttDb from './ganttDb'; -describe('when using the ganttDb', function () { - beforeEach(function () { - ganttDb.clear() - }) +describe('when using the ganttDb', function() { + beforeEach(function() { + ganttDb.clear(); + }); - describe('when using relative times', function () { + describe('when using relative times', function() { it.each` - diff | date | expected - ${' 1d'} | ${moment('2019-01-01')} | ${moment('2019-01-02').toDate()} - ${' 1w'} | ${moment('2019-01-01')} | ${moment('2019-01-08').toDate()} + diff | date | expected + ${' 1d'} | ${moment('2019-01-01')} | ${moment('2019-01-02').toDate()} + ${' 1w'} | ${moment('2019-01-01')} | ${moment('2019-01-08').toDate()} `('should add $diff to $date resulting in $expected', ({ diff, date, expected }) => { - expect(ganttDb.durationToDate(diff, date)).toEqual(expected) -}) - }) + expect(ganttDb.durationToDate(diff, date)).toEqual(expected); + }); + }); - describe('when calling the clear function', function () { - beforeEach(function () { - ganttDb.setDateFormat('YYYY-MM-DD') - ganttDb.enableInclusiveEndDates() - ganttDb.setExcludes('weekends 2019-02-06,friday') - ganttDb.addSection('weekends skip test') - ganttDb.addTask('test1', 'id1,2019-02-01,1d') - ganttDb.addTask('test2', 'id2,after id1,2d') - ganttDb.clear() - }) + describe('when calling the clear function', function() { + beforeEach(function() { + ganttDb.setDateFormat('YYYY-MM-DD'); + ganttDb.enableInclusiveEndDates(); + ganttDb.setExcludes('weekends 2019-02-06,friday'); + ganttDb.addSection('weekends skip test'); + ganttDb.addTask('test1', 'id1,2019-02-01,1d'); + ganttDb.addTask('test2', 'id2,after id1,2d'); + ganttDb.clear(); + }); it.each` fn | expected @@ -38,9 +38,9 @@ describe('when using the ganttDb', function () { ${'getSections'} | ${[]} ${'endDatesAreInclusive'} | ${false} `('should clear $fn', ({ fn, expected }) => { - expect(ganttDb[ fn ]()).toEqual(expected) -}) - }) + expect(ganttDb[fn]()).toEqual(expected); + }); + }); it.each` testName | section | taskName | taskData | expStartDate | expEndDate | expId | expTask @@ -52,135 +52,148 @@ describe('when using the ganttDb', function () { ${'should handle duration (weeks) instead of fixed date to determine end date'} | ${'testa1'} | ${'test1'} | ${'id1,2013-01-01,2w'} | ${new Date(2013, 0, 1)} | ${new Date(2013, 0, 15)} | ${'id1'} | ${'test1'} ${'should handle fixed dates without id'} | ${'testa1'} | ${'test1'} | ${'2013-01-01,2013-01-12'} | ${new Date(2013, 0, 1)} | ${new Date(2013, 0, 12)} | ${'task1'} | ${'test1'} ${'should handle duration instead of a fixed date to determine end date without id'} | ${'testa1'} | ${'test1'} | ${'2013-01-01,4d'} | ${new Date(2013, 0, 1)} | ${new Date(2013, 0, 5)} | ${'task1'} | ${'test1'} -`('$testName', ({ section, taskName, taskData, expStartDate, expEndDate, expId, expTask }) => { - ganttDb.setDateFormat('YYYY-MM-DD') - ganttDb.addSection(section) - ganttDb.addTask(taskName, taskData) - const tasks = ganttDb.getTasks() - expect(tasks[0].startTime).toEqual(expStartDate) - expect(tasks[0].endTime).toEqual(expEndDate) - expect(tasks[0].id).toEqual(expId) - expect(tasks[0].task).toEqual(expTask) -}) + `('$testName', ({ section, taskName, taskData, expStartDate, expEndDate, expId, expTask }) => { + ganttDb.setDateFormat('YYYY-MM-DD'); + ganttDb.addSection(section); + ganttDb.addTask(taskName, taskData); + const tasks = ganttDb.getTasks(); + expect(tasks[0].startTime).toEqual(expStartDate); + expect(tasks[0].endTime).toEqual(expEndDate); + expect(tasks[0].id).toEqual(expId); + expect(tasks[0].task).toEqual(expTask); + }); it.each` - section | taskName1 | taskName2 | taskData1 | taskData2 | expStartDate2 | expEndDate2 | expId2 | expTask2 - ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'id2,after id1,1d'} | ${new Date(2013, 0, 15)} | ${undefined} | ${'id2'} | ${'test2'} - ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'id2,after id3,1d'} | ${new Date((new Date()).setHours(0, 0, 0, 0))} | ${undefined} | ${'id2'} | ${'test2'} - ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'after id1,1d'} | ${new Date(2013, 0, 15)} | ${undefined} | ${'task1'} | ${'test2'} - ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'2013-01-26'} | ${new Date(2013, 0, 15)} | ${new Date(2013, 0, 26)} | ${'task1'} | ${'test2'} - ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'2d'} | ${new Date(2013, 0, 15)} | ${new Date(2013, 0, 17)} | ${'task1'} | ${'test2'} -`('$testName', ({ section, taskName1, taskName2, taskData1, taskData2, expStartDate2, expEndDate2, expId2, expTask2 }) => { - ganttDb.setDateFormat('YYYY-MM-DD') - ganttDb.addSection(section) - ganttDb.addTask(taskName1, taskData1) - ganttDb.addTask(taskName2, taskData2) - const tasks = ganttDb.getTasks() - expect(tasks[1].startTime).toEqual(expStartDate2) - if (!expEndDate2 === undefined) { - expect(tasks[1].endTime).toEqual(expEndDate2) - } - expect(tasks[1].id).toEqual(expId2) - expect(tasks[1].task).toEqual(expTask2) -}) + section | taskName1 | taskName2 | taskData1 | taskData2 | expStartDate2 | expEndDate2 | expId2 | expTask2 + ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'id2,after id1,1d'} | ${new Date(2013, 0, 15)} | ${undefined} | ${'id2'} | ${'test2'} + ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'id2,after id3,1d'} | ${new Date(new Date().setHours(0, 0, 0, 0))} | ${undefined} | ${'id2'} | ${'test2'} + ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'after id1,1d'} | ${new Date(2013, 0, 15)} | ${undefined} | ${'task1'} | ${'test2'} + ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'2013-01-26'} | ${new Date(2013, 0, 15)} | ${new Date(2013, 0, 26)} | ${'task1'} | ${'test2'} + ${'testa1'} | ${'test1'} | ${'test2'} | ${'id1,2013-01-01,2w'} | ${'2d'} | ${new Date(2013, 0, 15)} | ${new Date(2013, 0, 17)} | ${'task1'} | ${'test2'} + `( + '$testName', + ({ + section, + taskName1, + taskName2, + taskData1, + taskData2, + expStartDate2, + expEndDate2, + expId2, + expTask2 + }) => { + ganttDb.setDateFormat('YYYY-MM-DD'); + ganttDb.addSection(section); + ganttDb.addTask(taskName1, taskData1); + ganttDb.addTask(taskName2, taskData2); + const tasks = ganttDb.getTasks(); + expect(tasks[1].startTime).toEqual(expStartDate2); + if (!expEndDate2 === undefined) { + expect(tasks[1].endTime).toEqual(expEndDate2); + } + expect(tasks[1].id).toEqual(expId2); + expect(tasks[1].task).toEqual(expTask2); + } + ); - it('should handle relative start date based on id regardless of sections', function () { - ganttDb.setDateFormat('YYYY-MM-DD') - ganttDb.addSection('testa1') - ganttDb.addTask('test1', 'id1,2013-01-01,2w') - ganttDb.addTask('test2', 'id2,after id3,1d') - ganttDb.addSection('testa2') - ganttDb.addTask('test3', 'id3,after id1,2d') + it('should handle relative start date based on id regardless of sections', function() { + ganttDb.setDateFormat('YYYY-MM-DD'); + ganttDb.addSection('testa1'); + ganttDb.addTask('test1', 'id1,2013-01-01,2w'); + ganttDb.addTask('test2', 'id2,after id3,1d'); + ganttDb.addSection('testa2'); + ganttDb.addTask('test3', 'id3,after id1,2d'); - const tasks = ganttDb.getTasks() + const tasks = ganttDb.getTasks(); - expect(tasks[1].startTime).toEqual(new Date(2013, 0, 17)) - expect(tasks[1].endTime).toEqual(new Date(2013, 0, 18)) - expect(tasks[1].id).toEqual('id2') - expect(tasks[1].task).toEqual('test2') + expect(tasks[1].startTime).toEqual(new Date(2013, 0, 17)); + expect(tasks[1].endTime).toEqual(new Date(2013, 0, 18)); + expect(tasks[1].id).toEqual('id2'); + expect(tasks[1].task).toEqual('test2'); - expect(tasks[2].id).toEqual('id3') - expect(tasks[2].task).toEqual('test3') - expect(tasks[2].startTime).toEqual(new Date(2013, 0, 15)) - expect(tasks[2].endTime).toEqual(new Date(2013, 0, 17)) - }) - it('should ignore weekends', function () { - ganttDb.setDateFormat('YYYY-MM-DD') - ganttDb.setExcludes('weekends 2019-02-06,friday') - ganttDb.addSection('weekends skip test') - ganttDb.addTask('test1', 'id1,2019-02-01,1d') - ganttDb.addTask('test2', 'id2,after id1,2d') - ganttDb.addTask('test3', 'id3,after id2,7d') - ganttDb.addTask('test4', 'id4,2019-02-01,2019-02-20') // Fixed endTime - ganttDb.addTask('test5', 'id5,after id4,1d') - ganttDb.addSection('full ending taks on last day') - ganttDb.addTask('test6', 'id6,2019-02-13,2d') - ganttDb.addTask('test7', 'id7,after id6,1d') + expect(tasks[2].id).toEqual('id3'); + expect(tasks[2].task).toEqual('test3'); + expect(tasks[2].startTime).toEqual(new Date(2013, 0, 15)); + expect(tasks[2].endTime).toEqual(new Date(2013, 0, 17)); + }); + it('should ignore weekends', function() { + ganttDb.setDateFormat('YYYY-MM-DD'); + ganttDb.setExcludes('weekends 2019-02-06,friday'); + ganttDb.addSection('weekends skip test'); + ganttDb.addTask('test1', 'id1,2019-02-01,1d'); + ganttDb.addTask('test2', 'id2,after id1,2d'); + ganttDb.addTask('test3', 'id3,after id2,7d'); + ganttDb.addTask('test4', 'id4,2019-02-01,2019-02-20'); // Fixed endTime + ganttDb.addTask('test5', 'id5,after id4,1d'); + ganttDb.addSection('full ending taks on last day'); + ganttDb.addTask('test6', 'id6,2019-02-13,2d'); + ganttDb.addTask('test7', 'id7,after id6,1d'); - const tasks = ganttDb.getTasks() + const tasks = ganttDb.getTasks(); - expect(tasks[0].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()) - expect(tasks[0].endTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate()) - expect(tasks[0].renderEndTime).toEqual(moment('2019-02-02', 'YYYY-MM-DD').toDate()) - expect(tasks[0].id).toEqual('id1') - expect(tasks[0].task).toEqual('test1') + expect(tasks[0].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()); + expect(tasks[0].endTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate()); + expect(tasks[0].renderEndTime).toEqual(moment('2019-02-02', 'YYYY-MM-DD').toDate()); + expect(tasks[0].id).toEqual('id1'); + expect(tasks[0].task).toEqual('test1'); - expect(tasks[1].startTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate()) - expect(tasks[1].endTime).toEqual(moment('2019-02-07', 'YYYY-MM-DD').toDate()) - expect(tasks[1].renderEndTime).toEqual(moment('2019-02-06', 'YYYY-MM-DD').toDate()) - expect(tasks[1].id).toEqual('id2') - expect(tasks[1].task).toEqual('test2') + expect(tasks[1].startTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate()); + expect(tasks[1].endTime).toEqual(moment('2019-02-07', 'YYYY-MM-DD').toDate()); + expect(tasks[1].renderEndTime).toEqual(moment('2019-02-06', 'YYYY-MM-DD').toDate()); + expect(tasks[1].id).toEqual('id2'); + expect(tasks[1].task).toEqual('test2'); - expect(tasks[2].startTime).toEqual(moment('2019-02-07', 'YYYY-MM-DD').toDate()) - expect(tasks[2].endTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate()) - expect(tasks[2].renderEndTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate()) - expect(tasks[2].id).toEqual('id3') - expect(tasks[2].task).toEqual('test3') + expect(tasks[2].startTime).toEqual(moment('2019-02-07', 'YYYY-MM-DD').toDate()); + expect(tasks[2].endTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate()); + expect(tasks[2].renderEndTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate()); + expect(tasks[2].id).toEqual('id3'); + expect(tasks[2].task).toEqual('test3'); - expect(tasks[3].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()) - expect(tasks[3].endTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate()) - expect(tasks[3].renderEndTime).toBeNull() // Fixed end - expect(tasks[3].id).toEqual('id4') - expect(tasks[3].task).toEqual('test4') + expect(tasks[3].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()); + expect(tasks[3].endTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate()); + expect(tasks[3].renderEndTime).toBeNull(); // Fixed end + expect(tasks[3].id).toEqual('id4'); + expect(tasks[3].task).toEqual('test4'); - expect(tasks[4].startTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate()) - expect(tasks[4].endTime).toEqual(moment('2019-02-21', 'YYYY-MM-DD').toDate()) - expect(tasks[4].renderEndTime).toEqual(moment('2019-02-21', 'YYYY-MM-DD').toDate()) - expect(tasks[4].id).toEqual('id5') - expect(tasks[4].task).toEqual('test5') + expect(tasks[4].startTime).toEqual(moment('2019-02-20', 'YYYY-MM-DD').toDate()); + expect(tasks[4].endTime).toEqual(moment('2019-02-21', 'YYYY-MM-DD').toDate()); + expect(tasks[4].renderEndTime).toEqual(moment('2019-02-21', 'YYYY-MM-DD').toDate()); + expect(tasks[4].id).toEqual('id5'); + expect(tasks[4].task).toEqual('test5'); - expect(tasks[5].startTime).toEqual(moment('2019-02-13', 'YYYY-MM-DD').toDate()) - expect(tasks[5].endTime).toEqual(moment('2019-02-18', 'YYYY-MM-DD').toDate()) - expect(tasks[5].renderEndTime).toEqual(moment('2019-02-15', 'YYYY-MM-DD').toDate()) - expect(tasks[5].id).toEqual('id6') - expect(tasks[5].task).toEqual('test6') + expect(tasks[5].startTime).toEqual(moment('2019-02-13', 'YYYY-MM-DD').toDate()); + expect(tasks[5].endTime).toEqual(moment('2019-02-18', 'YYYY-MM-DD').toDate()); + expect(tasks[5].renderEndTime).toEqual(moment('2019-02-15', 'YYYY-MM-DD').toDate()); + expect(tasks[5].id).toEqual('id6'); + expect(tasks[5].task).toEqual('test6'); - expect(tasks[6].startTime).toEqual(moment('2019-02-18', 'YYYY-MM-DD').toDate()) - expect(tasks[6].endTime).toEqual(moment('2019-02-19', 'YYYY-MM-DD').toDate()) - expect(tasks[6].id).toEqual('id7') - expect(tasks[6].task).toEqual('test7') - }) + expect(tasks[6].startTime).toEqual(moment('2019-02-18', 'YYYY-MM-DD').toDate()); + expect(tasks[6].endTime).toEqual(moment('2019-02-19', 'YYYY-MM-DD').toDate()); + expect(tasks[6].id).toEqual('id7'); + expect(tasks[6].task).toEqual('test7'); + }); - describe('when setting inclusive end dates', function () { - beforeEach(function () { - ganttDb.setDateFormat('YYYY-MM-DD') - ganttDb.enableInclusiveEndDates() - ganttDb.addTask('test1', 'id1,2019-02-01,1d') - ganttDb.addTask('test2', 'id2,2019-02-01,2019-02-03') - }) - it('should automatically add one day to all end dates', function () { - const tasks = ganttDb.getTasks() - expect(tasks[0].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()) - expect(tasks[0].endTime).toEqual(moment('2019-02-02', 'YYYY-MM-DD').toDate()) - expect(tasks[0].id).toEqual('id1') - expect(tasks[0].task).toEqual('test1') + describe('when setting inclusive end dates', function() { + beforeEach(function() { + ganttDb.setDateFormat('YYYY-MM-DD'); + ganttDb.enableInclusiveEndDates(); + ganttDb.addTask('test1', 'id1,2019-02-01,1d'); + ganttDb.addTask('test2', 'id2,2019-02-01,2019-02-03'); + }); + it('should automatically add one day to all end dates', function() { + const tasks = ganttDb.getTasks(); + expect(tasks[0].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()); + expect(tasks[0].endTime).toEqual(moment('2019-02-02', 'YYYY-MM-DD').toDate()); + expect(tasks[0].id).toEqual('id1'); + expect(tasks[0].task).toEqual('test1'); - expect(tasks[1].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()) - expect(tasks[1].endTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate()) - expect(tasks[1].renderEndTime).toBeNull() // Fixed end - expect(tasks[1].manualEndTime).toBeTruthy() - expect(tasks[1].id).toEqual('id2') - expect(tasks[1].task).toEqual('test2') - }) - }) -}) + expect(tasks[1].startTime).toEqual(moment('2019-02-01', 'YYYY-MM-DD').toDate()); + expect(tasks[1].endTime).toEqual(moment('2019-02-04', 'YYYY-MM-DD').toDate()); + expect(tasks[1].renderEndTime).toBeNull(); // Fixed end + expect(tasks[1].manualEndTime).toBeTruthy(); + expect(tasks[1].id).toEqual('id2'); + expect(tasks[1].task).toEqual('test2'); + }); + }); +}); diff --git a/src/diagrams/gantt/ganttRenderer.js b/src/diagrams/gantt/ganttRenderer.js index c9349f483..beee82e17 100644 --- a/src/diagrams/gantt/ganttRenderer.js +++ b/src/diagrams/gantt/ganttRenderer.js @@ -1,9 +1,9 @@ -import * as d3 from 'd3' +import * as d3 from 'd3'; -import { parser } from './parser/gantt' -import ganttDb from './ganttDb' +import { parser } from './parser/gantt'; +import ganttDb from './ganttDb'; -parser.yy = ganttDb +parser.yy = ganttDb; const conf = { titleTopMargin: 25, @@ -15,287 +15,316 @@ const conf = { gridLineStartPadding: 35, fontSize: 11, fontFamily: '"Open-Sans", "sans-serif"' -} -export const setConf = function (cnf) { - const keys = Object.keys(cnf) +}; +export const setConf = function(cnf) { + const keys = Object.keys(cnf); - keys.forEach(function (key) { - conf[key] = cnf[key] - }) -} -let w -export const draw = function (text, id) { - parser.yy.clear() - parser.parse(text) + keys.forEach(function(key) { + conf[key] = cnf[key]; + }); +}; +let w; +export const draw = function(text, id) { + parser.yy.clear(); + parser.parse(text); - const elem = document.getElementById(id) - w = elem.parentElement.offsetWidth + const elem = document.getElementById(id); + w = elem.parentElement.offsetWidth; if (typeof w === 'undefined') { - w = 1200 + w = 1200; } if (typeof conf.useWidth !== 'undefined') { - w = conf.useWidth + w = conf.useWidth; } - const taskArray = parser.yy.getTasks() + const taskArray = parser.yy.getTasks(); // Set height based on number of tasks - const h = taskArray.length * (conf.barHeight + conf.barGap) + 2 * conf.topPadding + const h = taskArray.length * (conf.barHeight + conf.barGap) + 2 * conf.topPadding; - elem.setAttribute('height', '100%') + elem.setAttribute('height', '100%'); // Set viewBox - elem.setAttribute('viewBox', '0 0 ' + w + ' ' + h) - const svg = d3.select(`[id="${id}"]`) + elem.setAttribute('viewBox', '0 0 ' + w + ' ' + h); + const svg = d3.select(`[id="${id}"]`); // Set timescale - const timeScale = d3.scaleTime() - .domain([d3.min(taskArray, function (d) { - return d.startTime - }), - d3.max(taskArray, function (d) { - return d.endTime - })]) - .rangeRound([0, w - conf.leftPadding - conf.rightPadding]) + const timeScale = d3 + .scaleTime() + .domain([ + d3.min(taskArray, function(d) { + return d.startTime; + }), + d3.max(taskArray, function(d) { + return d.endTime; + }) + ]) + .rangeRound([0, w - conf.leftPadding - conf.rightPadding]); - let categories = [] + let categories = []; for (let i = 0; i < taskArray.length; i++) { - categories.push(taskArray[i].type) + categories.push(taskArray[i].type); } - const catsUnfiltered = categories // for vert labels + const catsUnfiltered = categories; // for vert labels - categories = checkUnique(categories) + categories = checkUnique(categories); - makeGant(taskArray, w, h) + makeGant(taskArray, w, h); if (typeof conf.useWidth !== 'undefined') { - elem.setAttribute('width', w) + elem.setAttribute('width', w); } - svg.append('text') + svg + .append('text') .text(parser.yy.getTitle()) .attr('x', w / 2) .attr('y', conf.titleTopMargin) - .attr('class', 'titleText') + .attr('class', 'titleText'); - function makeGant (tasks, pageWidth, pageHeight) { - const barHeight = conf.barHeight - const gap = barHeight + conf.barGap - const topPadding = conf.topPadding - const leftPadding = conf.leftPadding + function makeGant(tasks, pageWidth, pageHeight) { + const barHeight = conf.barHeight; + const gap = barHeight + conf.barGap; + const topPadding = conf.topPadding; + const leftPadding = conf.leftPadding; - const colorScale = d3.scaleLinear() + const colorScale = d3 + .scaleLinear() .domain([0, categories.length]) .range(['#00B9FA', '#F95002']) - .interpolate(d3.interpolateHcl) + .interpolate(d3.interpolateHcl); - makeGrid(leftPadding, topPadding, pageWidth, pageHeight) - drawRects(tasks, gap, topPadding, leftPadding, barHeight, colorScale, pageWidth, pageHeight) - vertLabels(gap, topPadding, leftPadding, barHeight, colorScale) - drawToday(leftPadding, topPadding, pageWidth, pageHeight) + makeGrid(leftPadding, topPadding, pageWidth, pageHeight); + drawRects(tasks, gap, topPadding, leftPadding, barHeight, colorScale, pageWidth, pageHeight); + vertLabels(gap, topPadding, leftPadding, barHeight, colorScale); + drawToday(leftPadding, topPadding, pageWidth, pageHeight); } - function drawRects (theArray, theGap, theTopPad, theSidePad, theBarHeight, theColorScale, w, h) { + function drawRects(theArray, theGap, theTopPad, theSidePad, theBarHeight, theColorScale, w, h) { // Draw background rects covering the entire width of the graph, these form the section rows. - svg.append('g') + svg + .append('g') .selectAll('rect') .data(theArray) .enter() .append('rect') .attr('x', 0) - .attr('y', function (d, i) { - return i * theGap + theTopPad - 2 + .attr('y', function(d, i) { + return i * theGap + theTopPad - 2; }) - .attr('width', function () { - return w - conf.rightPadding / 2 + .attr('width', function() { + return w - conf.rightPadding / 2; }) .attr('height', theGap) - .attr('class', function (d) { + .attr('class', function(d) { for (let i = 0; i < categories.length; i++) { if (d.type === categories[i]) { - return 'section section' + (i % conf.numberSectionStyles) + return 'section section' + (i % conf.numberSectionStyles); } } - return 'section section0' - }) + return 'section section0'; + }); // Draw the rects representing the tasks - const rectangles = svg.append('g') + const rectangles = svg + .append('g') .selectAll('rect') .data(theArray) - .enter() + .enter(); - rectangles.append('rect') - .attr('id', function (d) { return d.id }) + rectangles + .append('rect') + .attr('id', function(d) { + return d.id; + }) .attr('rx', 3) .attr('ry', 3) - .attr('x', function (d) { + .attr('x', function(d) { if (d.milestone) { - return timeScale(d.startTime) + theSidePad + (0.5 * (timeScale(d.endTime) - timeScale(d.startTime))) - (0.5 * theBarHeight) + return ( + timeScale(d.startTime) + + theSidePad + + 0.5 * (timeScale(d.endTime) - timeScale(d.startTime)) - + 0.5 * theBarHeight + ); } - return timeScale(d.startTime) + theSidePad + return timeScale(d.startTime) + theSidePad; }) - .attr('y', function (d, i) { - return i * theGap + theTopPad + .attr('y', function(d, i) { + return i * theGap + theTopPad; }) - .attr('width', function (d) { + .attr('width', function(d) { if (d.milestone) { - return theBarHeight + return theBarHeight; } - return (timeScale(d.renderEndTime || d.endTime) - timeScale(d.startTime)) + return timeScale(d.renderEndTime || d.endTime) - timeScale(d.startTime); }) .attr('height', theBarHeight) - .attr('transform-origin', function (d, i) { - return (timeScale(d.startTime) + theSidePad + 0.5 * (timeScale(d.endTime) - timeScale(d.startTime))).toString() + 'px ' + (i * theGap + theTopPad + 0.5 * theBarHeight).toString() + 'px' + .attr('transform-origin', function(d, i) { + return ( + ( + timeScale(d.startTime) + + theSidePad + + 0.5 * (timeScale(d.endTime) - timeScale(d.startTime)) + ).toString() + + 'px ' + + (i * theGap + theTopPad + 0.5 * theBarHeight).toString() + + 'px' + ); }) - .attr('class', function (d) { - const res = 'task' + .attr('class', function(d) { + const res = 'task'; - let classStr = '' + let classStr = ''; if (d.classes.length > 0) { - classStr = d.classes.join(' ') + classStr = d.classes.join(' '); } - let secNum = 0 + let secNum = 0; for (let i = 0; i < categories.length; i++) { if (d.type === categories[i]) { - secNum = (i % conf.numberSectionStyles) + secNum = i % conf.numberSectionStyles; } } - let taskClass = '' + let taskClass = ''; if (d.active) { if (d.crit) { - taskClass += ' activeCrit' + taskClass += ' activeCrit'; } else { - taskClass = ' active' + taskClass = ' active'; } } else if (d.done) { if (d.crit) { - taskClass = ' doneCrit' + taskClass = ' doneCrit'; } else { - taskClass = ' done' + taskClass = ' done'; } } else { if (d.crit) { - taskClass += ' crit' + taskClass += ' crit'; } } if (taskClass.length === 0) { - taskClass = ' task' + taskClass = ' task'; } if (d.milestone) { - taskClass = ' milestone ' + taskClass + taskClass = ' milestone ' + taskClass; } - taskClass += secNum + taskClass += secNum; - taskClass += ' ' + classStr + taskClass += ' ' + classStr; - return res + taskClass - }) + return res + taskClass; + }); // Append task labels - rectangles.append('text') - .attr('id', function (d) { return d.id + '-text' }) - .text(function (d) { - return d.task + rectangles + .append('text') + .attr('id', function(d) { + return d.id + '-text'; + }) + .text(function(d) { + return d.task; }) .attr('font-size', conf.fontSize) - .attr('x', function (d) { - let startX = timeScale(d.startTime) - let endX = timeScale(d.renderEndTime || d.endTime) + .attr('x', function(d) { + let startX = timeScale(d.startTime); + let endX = timeScale(d.renderEndTime || d.endTime); if (d.milestone) { - startX += (0.5 * (timeScale(d.endTime) - timeScale(d.startTime))) - (0.5 * theBarHeight) + startX += 0.5 * (timeScale(d.endTime) - timeScale(d.startTime)) - 0.5 * theBarHeight; } if (d.milestone) { - endX = startX + theBarHeight + endX = startX + theBarHeight; } - const textWidth = this.getBBox().width + const textWidth = this.getBBox().width; // Check id text width > width of rectangle - if (textWidth > (endX - startX)) { + if (textWidth > endX - startX) { if (endX + textWidth + 1.5 * conf.leftPadding > w) { - return startX + theSidePad - 5 + return startX + theSidePad - 5; } else { - return endX + theSidePad + 5 + return endX + theSidePad + 5; } } else { - return (endX - startX) / 2 + startX + theSidePad + return (endX - startX) / 2 + startX + theSidePad; } }) - .attr('y', function (d, i) { - return i * theGap + (conf.barHeight / 2) + (conf.fontSize / 2 - 2) + theTopPad + .attr('y', function(d, i) { + return i * theGap + conf.barHeight / 2 + (conf.fontSize / 2 - 2) + theTopPad; }) .attr('text-height', theBarHeight) - .attr('class', function (d) { - const startX = timeScale(d.startTime) - let endX = timeScale(d.endTime) + .attr('class', function(d) { + const startX = timeScale(d.startTime); + let endX = timeScale(d.endTime); if (d.milestone) { - endX = startX + theBarHeight + endX = startX + theBarHeight; } - const textWidth = this.getBBox().width + const textWidth = this.getBBox().width; - let classStr = '' + let classStr = ''; if (d.classes.length > 0) { - classStr = d.classes.join(' ') + classStr = d.classes.join(' '); } - let secNum = 0 + let secNum = 0; for (let i = 0; i < categories.length; i++) { if (d.type === categories[i]) { - secNum = (i % conf.numberSectionStyles) + secNum = i % conf.numberSectionStyles; } } - let taskType = '' + let taskType = ''; if (d.active) { if (d.crit) { - taskType = 'activeCritText' + secNum + taskType = 'activeCritText' + secNum; } else { - taskType = 'activeText' + secNum + taskType = 'activeText' + secNum; } } if (d.done) { if (d.crit) { - taskType = taskType + ' doneCritText' + secNum + taskType = taskType + ' doneCritText' + secNum; } else { - taskType = taskType + ' doneText' + secNum + taskType = taskType + ' doneText' + secNum; } } else { if (d.crit) { - taskType = taskType + ' critText' + secNum + taskType = taskType + ' critText' + secNum; } } if (d.milestone) { - taskType += ' milestoneText' + taskType += ' milestoneText'; } // Check id text width > width of rectangle - if (textWidth > (endX - startX)) { + if (textWidth > endX - startX) { if (endX + textWidth + 1.5 * conf.leftPadding > w) { - return classStr + ' taskTextOutsideLeft taskTextOutside' + secNum + ' ' + taskType + return classStr + ' taskTextOutsideLeft taskTextOutside' + secNum + ' ' + taskType; } else { - return classStr + ' taskTextOutsideRight taskTextOutside' + secNum + ' ' + taskType + return classStr + ' taskTextOutsideRight taskTextOutside' + secNum + ' ' + taskType; } } else { - return classStr + ' taskText taskText' + secNum + ' ' + taskType + return classStr + ' taskText taskText' + secNum + ' ' + taskType; } - }) + }); } - function makeGrid (theSidePad, theTopPad, w, h) { - let xAxis = d3.axisBottom(timeScale) + function makeGrid(theSidePad, theTopPad, w, h) { + let xAxis = d3 + .axisBottom(timeScale) .tickSize(-h + theTopPad + conf.gridLineStartPadding) - .tickFormat(d3.timeFormat(parser.yy.getAxisFormat() || conf.axisFormat || '%Y-%m-%d')) + .tickFormat(d3.timeFormat(parser.yy.getAxisFormat() || conf.axisFormat || '%Y-%m-%d')); - svg.append('g') + svg + .append('g') .attr('class', 'grid') .attr('transform', 'translate(' + theSidePad + ', ' + (h - 50) + ')') .call(xAxis) @@ -304,90 +333,92 @@ export const draw = function (text, id) { .attr('fill', '#000') .attr('stroke', 'none') .attr('font-size', 10) - .attr('dy', '1em') + .attr('dy', '1em'); } - function vertLabels (theGap, theTopPad) { - const numOccurances = [] - let prevGap = 0 + function vertLabels(theGap, theTopPad) { + const numOccurances = []; + let prevGap = 0; for (let i = 0; i < categories.length; i++) { - numOccurances[i] = [categories[i], getCount(categories[i], catsUnfiltered)] + numOccurances[i] = [categories[i], getCount(categories[i], catsUnfiltered)]; } - svg.append('g') // without doing this, impossible to put grid lines behind text + svg + .append('g') // without doing this, impossible to put grid lines behind text .selectAll('text') .data(numOccurances) .enter() .append('text') - .text(function (d) { - return d[0] + .text(function(d) { + return d[0]; }) .attr('x', 10) - .attr('y', function (d, i) { + .attr('y', function(d, i) { if (i > 0) { for (let j = 0; j < i; j++) { - prevGap += numOccurances[i - 1][1] - return d[1] * theGap / 2 + prevGap * theGap + theTopPad + prevGap += numOccurances[i - 1][1]; + return (d[1] * theGap) / 2 + prevGap * theGap + theTopPad; } } else { - return d[1] * theGap / 2 + theTopPad + return (d[1] * theGap) / 2 + theTopPad; } }) - .attr('class', function (d) { + .attr('class', function(d) { for (let i = 0; i < categories.length; i++) { if (d[0] === categories[i]) { - return 'sectionTitle sectionTitle' + (i % conf.numberSectionStyles) + return 'sectionTitle sectionTitle' + (i % conf.numberSectionStyles); } } - return 'sectionTitle' - }) + return 'sectionTitle'; + }); } - function drawToday (theSidePad, theTopPad, w, h) { - const todayG = svg.append('g') - .attr('class', 'today') + function drawToday(theSidePad, theTopPad, w, h) { + const todayG = svg.append('g').attr('class', 'today'); - const today = new Date() + const today = new Date(); - todayG.append('line') + todayG + .append('line') .attr('x1', timeScale(today) + theSidePad) .attr('x2', timeScale(today) + theSidePad) .attr('y1', conf.titleTopMargin) .attr('y2', h - conf.titleTopMargin) - .attr('class', 'today') + .attr('class', 'today'); } // from this stackexchange question: http://stackoverflow.com/questions/1890203/unique-for-arrays-in-javascript - function checkUnique (arr) { - const hash = {} - const result = [] + function checkUnique(arr) { + const hash = {}; + const result = []; for (let i = 0, l = arr.length; i < l; ++i) { - if (!hash.hasOwnProperty(arr[i])) { // it works with objects! in FF, at least - hash[arr[i]] = true - result.push(arr[i]) + if (!hash.hasOwnProperty(arr[i])) { + // it works with objects! in FF, at least + hash[arr[i]] = true; + result.push(arr[i]); } } - return result + return result; } // from this stackexchange question: http://stackoverflow.com/questions/14227981/count-how-many-strings-in-an-array-have-duplicates-in-the-same-array - function getCounts (arr) { - let i = arr.length // const to loop over - const obj = {} // obj to store results + function getCounts(arr) { + let i = arr.length; // const to loop over + const obj = {}; // obj to store results while (i) { - obj[arr[--i]] = (obj[arr[i]] || 0) + 1 // count occurrences + obj[arr[--i]] = (obj[arr[i]] || 0) + 1; // count occurrences } - return obj + return obj; } // get specific from everything - function getCount (word, arr) { - return getCounts(arr)[word] || 0 + function getCount(word, arr) { + return getCounts(arr)[word] || 0; } -} +}; export default { setConf, draw -} +}; diff --git a/src/diagrams/gantt/parser/gantt.spec.js b/src/diagrams/gantt/parser/gantt.spec.js index 7a28aeb6c..51d2c0884 100644 --- a/src/diagrams/gantt/parser/gantt.spec.js +++ b/src/diagrams/gantt/parser/gantt.spec.js @@ -1,50 +1,52 @@ /* eslint-env jasmine */ /* eslint-disable no-eval */ -import { parser } from './gantt' -import ganttDb from '../ganttDb' +import { parser } from './gantt'; +import ganttDb from '../ganttDb'; -const parserFnConstructor = (str) => { +const parserFnConstructor = str => { return () => { - parser.parse(str) - } -} + parser.parse(str); + }; +}; -describe('when parsing a gantt diagram it', function () { - beforeEach(function () { - parser.yy = ganttDb - parser.yy.clear() - }) +describe('when parsing a gantt diagram it', function() { + beforeEach(function() { + parser.yy = ganttDb; + parser.yy.clear(); + }); - it('should handle a dateFormat definition', function () { - const str = 'gantt\ndateFormat yyyy-mm-dd' + it('should handle a dateFormat definition', function() { + const str = 'gantt\ndateFormat yyyy-mm-dd'; - expect(parserFnConstructor(str)).not.toThrow() - }) + expect(parserFnConstructor(str)).not.toThrow(); + }); - it('should handle a inclusive end date definition', function () { - const str = 'gantt\ndateFormat yyyy-mm-dd\ninclusiveEndDates' + it('should handle a inclusive end date definition', function() { + const str = 'gantt\ndateFormat yyyy-mm-dd\ninclusiveEndDates'; - expect(parserFnConstructor(str)).not.toThrow() - }) - it('should handle a title definition', function () { - const str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid' + expect(parserFnConstructor(str)).not.toThrow(); + }); + it('should handle a title definition', function() { + const str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid'; - expect(parserFnConstructor(str)).not.toThrow() - }) - it('should handle an excludes definition', function () { - const str = 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid\nexcludes weekdays 2019-02-01' + expect(parserFnConstructor(str)).not.toThrow(); + }); + it('should handle an excludes definition', function() { + const str = + 'gantt\ndateFormat yyyy-mm-dd\ntitle Adding gantt diagram functionality to mermaid\nexcludes weekdays 2019-02-01'; - expect(parserFnConstructor(str)).not.toThrow() - }) - it('should handle a section definition', function () { - const str = 'gantt\n' + + expect(parserFnConstructor(str)).not.toThrow(); + }); + it('should handle a section definition', function() { + const str = + 'gantt\n' + 'dateFormat yyyy-mm-dd\n' + 'title Adding gantt diagram functionality to mermaid\n' + 'excludes weekdays 2019-02-01\n' + - 'section Documentation' + 'section Documentation'; - expect(parserFnConstructor(str)).not.toThrow() - }) + expect(parserFnConstructor(str)).not.toThrow(); + }); /** * Beslutsflöde inligt nedan. Obs bla bla bla * ``` @@ -56,22 +58,23 @@ describe('when parsing a gantt diagram it', function () { ``` * params bapa - a unique bapap */ - it('should handle a task definition', function () { - const str = 'gantt\n' + + it('should handle a task definition', function() { + const str = + 'gantt\n' + 'dateFormat YYYY-MM-DD\n' + 'title Adding gantt diagram functionality to mermaid\n' + 'section Documentation\n' + - 'Design jison grammar:des1, 2014-01-01, 2014-01-04' + 'Design jison grammar:des1, 2014-01-01, 2014-01-04'; - expect(parserFnConstructor(str)).not.toThrow() + expect(parserFnConstructor(str)).not.toThrow(); - const tasks = parser.yy.getTasks() + const tasks = parser.yy.getTasks(); - expect(tasks[0].startTime).toEqual(new Date(2014, 0, 1)) - expect(tasks[0].endTime).toEqual(new Date(2014, 0, 4)) - expect(tasks[0].id).toEqual('des1') - expect(tasks[0].task).toEqual('Design jison grammar') - }) + expect(tasks[0].startTime).toEqual(new Date(2014, 0, 1)); + expect(tasks[0].endTime).toEqual(new Date(2014, 0, 4)); + expect(tasks[0].id).toEqual('des1'); + expect(tasks[0].task).toEqual('Design jison grammar'); + }); it.each` tags | milestone | done | crit | active ${'milestone'} | ${true} | ${false} | ${false} | ${false} @@ -79,25 +82,28 @@ describe('when parsing a gantt diagram it', function () { ${'crit'} | ${false} | ${false} | ${true} | ${false} ${'active'} | ${false} | ${false} | ${false} | ${true} ${'crit,milestone,done'} | ${true} | ${true} | ${true} | ${false} - `('should handle a task with tags $tags', ({ tags, milestone, done, crit, active }) => { - const str = 'gantt\n' + - 'dateFormat YYYY-MM-DD\n' + - 'title Adding gantt diagram functionality to mermaid\n' + - 'section Documentation\n' + - 'test task:' + tags + ', 2014-01-01, 2014-01-04' + `('should handle a task with tags $tags', ({ tags, milestone, done, crit, active }) => { + const str = + 'gantt\n' + + 'dateFormat YYYY-MM-DD\n' + + 'title Adding gantt diagram functionality to mermaid\n' + + 'section Documentation\n' + + 'test task:' + + tags + + ', 2014-01-01, 2014-01-04'; - const allowedTags = ['active', 'done', 'crit', 'milestone'] + const allowedTags = ['active', 'done', 'crit', 'milestone']; - expect(parserFnConstructor(str)).not.toThrow() + expect(parserFnConstructor(str)).not.toThrow(); - const tasks = parser.yy.getTasks() + const tasks = parser.yy.getTasks(); - allowedTags.forEach(function (t) { - if (eval(t)) { - expect(tasks[0][t]).toBeTruthy() - } else { - expect(tasks[0][t]).toBeFalsy() - } - }) -}) -}) + allowedTags.forEach(function(t) { + if (eval(t)) { + expect(tasks[0][t]).toBeTruthy(); + } else { + expect(tasks[0][t]).toBeFalsy(); + } + }); + }); +}); From 34de31195f40f8c68ea0a8d9843bf5d02d8a47bb Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:58:04 -0700 Subject: [PATCH 10/13] #931 Aligning with code standard --- src/diagrams/flowchart/flowDb.js | 482 +-- src/diagrams/flowchart/flowRenderer.js | 676 ++-- .../parser/flow-vertice-chaining.spec.js | 55 +- src/diagrams/flowchart/parser/flow.spec.js | 3187 +++++++++-------- .../flowchart/parser/subgraph.spec.js | 342 +- 5 files changed, 2415 insertions(+), 2327 deletions(-) diff --git a/src/diagrams/flowchart/flowDb.js b/src/diagrams/flowchart/flowDb.js index b9e397eca..8928ad42f 100644 --- a/src/diagrams/flowchart/flowDb.js +++ b/src/diagrams/flowchart/flowDb.js @@ -1,33 +1,33 @@ -import * as d3 from 'd3' -import { sanitizeUrl } from '@braintree/sanitize-url' -import { logger } from '../../logger' -import utils from '../../utils' -import { getConfig } from '../../config' +import * as d3 from 'd3'; +import { sanitizeUrl } from '@braintree/sanitize-url'; +import { logger } from '../../logger'; +import utils from '../../utils'; +import { getConfig } from '../../config'; -const config = getConfig() -let vertices = {} -let edges = [] -let classes = [] -let subGraphs = [] -let subGraphLookup = {} -let tooltips = {} -let subCount = 0 -let direction +const config = getConfig(); +let vertices = {}; +let edges = []; +let classes = []; +let subGraphs = []; +let subGraphLookup = {}; +let tooltips = {}; +let subCount = 0; +let direction; // Functions to be run after graph rendering -let funs = [] +let funs = []; const sanitize = text => { - let txt = text + let txt = text; if (config.securityLevel !== 'loose') { - txt = txt.replace(/
/g, '#br#') - txt = txt.replace(//g, '#br#') - txt = txt.replace(//g, '>') - txt = txt.replace(/=/g, '=') - txt = txt.replace(/#br#/g, '
') + txt = txt.replace(/
/g, '#br#'); + txt = txt.replace(//g, '#br#'); + txt = txt.replace(//g, '>'); + txt = txt.replace(/=/g, '='); + txt = txt.replace(/#br#/g, '
'); } - return txt -} + return txt; +}; /** * Function called by parser when a node definition has been found @@ -37,53 +37,53 @@ const sanitize = text => { * @param style * @param classes */ -export const addVertex = function (_id, text, type, style, classes) { - let txt - let id = _id +export const addVertex = function(_id, text, type, style, classes) { + let txt; + let id = _id; if (typeof id === 'undefined') { - return + return; } if (id.trim().length === 0) { - return + return; } - if (id[0].match(/\d/)) id = 's' + id + if (id[0].match(/\d/)) id = 's' + id; if (typeof vertices[id] === 'undefined') { - vertices[id] = { id: id, styles: [], classes: [] } + vertices[id] = { id: id, styles: [], classes: [] }; } if (typeof text !== 'undefined') { - txt = sanitize(text.trim()) + txt = sanitize(text.trim()); // strip quotes if string starts and exnds with a quote if (txt[0] === '"' && txt[txt.length - 1] === '"') { - txt = txt.substring(1, txt.length - 1) + txt = txt.substring(1, txt.length - 1); } - vertices[id].text = txt + vertices[id].text = txt; } else { if (!vertices[id].text) { - vertices[id].text = _id + vertices[id].text = _id; } } if (typeof type !== 'undefined') { - vertices[id].type = type + vertices[id].type = type; } if (typeof style !== 'undefined') { if (style !== null) { - style.forEach(function (s) { - vertices[id].styles.push(s) - }) + style.forEach(function(s) { + vertices[id].styles.push(s); + }); } } if (typeof classes !== 'undefined') { if (classes !== null) { - classes.forEach(function (s) { - vertices[id].classes.push(s) - }) + classes.forEach(function(s) { + vertices[id].classes.push(s); + }); } } -} +}; /** * Function called by parser when a link/edge definition has been found @@ -92,134 +92,138 @@ export const addVertex = function (_id, text, type, style, classes) { * @param type * @param linktext */ -export const addLink = function (_start, _end, type, linktext) { - let start = _start - let end = _end - if (start[0].match(/\d/)) start = 's' + start - if (end[0].match(/\d/)) end = 's' + end - logger.info('Got edge...', start, end) +export const addLink = function(_start, _end, type, linktext) { + let start = _start; + let end = _end; + if (start[0].match(/\d/)) start = 's' + start; + if (end[0].match(/\d/)) end = 's' + end; + logger.info('Got edge...', start, end); - const edge = { start: start, end: end, type: undefined, text: '' } - linktext = type.text + const edge = { start: start, end: end, type: undefined, text: '' }; + linktext = type.text; if (typeof linktext !== 'undefined') { - edge.text = sanitize(linktext.trim()) + edge.text = sanitize(linktext.trim()); // strip quotes if string starts and exnds with a quote if (edge.text[0] === '"' && edge.text[edge.text.length - 1] === '"') { - edge.text = edge.text.substring(1, edge.text.length - 1) + edge.text = edge.text.substring(1, edge.text.length - 1); } } if (typeof type !== 'undefined') { - edge.type = type.type - edge.stroke = type.stroke + edge.type = type.type; + edge.stroke = type.stroke; } - edges.push(edge) -} + edges.push(edge); +}; /** * Updates a link's line interpolation algorithm * @param pos * @param interpolate */ -export const updateLinkInterpolate = function (positions, interp) { - positions.forEach(function (pos) { +export const updateLinkInterpolate = function(positions, interp) { + positions.forEach(function(pos) { if (pos === 'default') { - edges.defaultInterpolate = interp + edges.defaultInterpolate = interp; } else { - edges[pos].interpolate = interp + edges[pos].interpolate = interp; } - }) -} + }); +}; /** * Updates a link with a style * @param pos * @param style */ -export const updateLink = function (positions, style) { - positions.forEach(function (pos) { +export const updateLink = function(positions, style) { + positions.forEach(function(pos) { if (pos === 'default') { - edges.defaultStyle = style + edges.defaultStyle = style; } else { if (utils.isSubstringInArray('fill', style) === -1) { - style.push('fill:none') + style.push('fill:none'); } - edges[pos].style = style + edges[pos].style = style; } - }) -} + }); +}; -export const addClass = function (id, style) { +export const addClass = function(id, style) { if (typeof classes[id] === 'undefined') { - classes[id] = { id: id, styles: [] } + classes[id] = { id: id, styles: [] }; } if (typeof style !== 'undefined') { if (style !== null) { - style.forEach(function (s) { - classes[id].styles.push(s) - }) + style.forEach(function(s) { + classes[id].styles.push(s); + }); } } -} +}; /** * Called by parser when a graph definition is found, stores the direction of the chart. * @param dir */ -export const setDirection = function (dir) { - direction = dir -} +export const setDirection = function(dir) { + direction = dir; +}; /** * Called by parser when a special node is found, e.g. a clickable element. * @param ids Comma separated list of ids * @param className Class to add */ -export const setClass = function (ids, className) { - ids.split(',').forEach(function (_id) { - let id = _id - if (_id[0].match(/\d/)) id = 's' + id +export const setClass = function(ids, className) { + ids.split(',').forEach(function(_id) { + let id = _id; + if (_id[0].match(/\d/)) id = 's' + id; if (typeof vertices[id] !== 'undefined') { - vertices[id].classes.push(className) + vertices[id].classes.push(className); } if (typeof subGraphLookup[id] !== 'undefined') { - subGraphLookup[id].classes.push(className) + subGraphLookup[id].classes.push(className); } - }) -} + }); +}; -const setTooltip = function (ids, tooltip) { - ids.split(',').forEach(function (id) { +const setTooltip = function(ids, tooltip) { + ids.split(',').forEach(function(id) { if (typeof tooltip !== 'undefined') { - tooltips[id] = sanitize(tooltip) + tooltips[id] = sanitize(tooltip); } - }) -} + }); +}; -const setClickFun = function (_id, functionName) { - let id = _id - if (_id[0].match(/\d/)) id = 's' + id +const setClickFun = function(_id, functionName) { + let id = _id; + if (_id[0].match(/\d/)) id = 's' + id; if (config.securityLevel !== 'loose') { - return + return; } if (typeof functionName === 'undefined') { - return + return; } if (typeof vertices[id] !== 'undefined') { - funs.push(function (element) { - const elem = document.querySelector(`[id="${id}"]`) + funs.push(function(element) { + const elem = document.querySelector(`[id="${id}"]`); if (elem !== null) { - elem.addEventListener('click', function () { - window[functionName](id) - }, false) + elem.addEventListener( + 'click', + function() { + window[functionName](id); + }, + false + ); } - }) + }); } -} +}; /** * Called by parser when a link is found. Adds the URL to the vertex data. @@ -227,24 +231,24 @@ const setClickFun = function (_id, functionName) { * @param linkStr URL to create a link for * @param tooltip Tooltip for the clickable element */ -export const setLink = function (ids, linkStr, tooltip) { - ids.split(',').forEach(function (_id) { - let id = _id - if (_id[0].match(/\d/)) id = 's' + id +export const setLink = function(ids, linkStr, tooltip) { + ids.split(',').forEach(function(_id) { + let id = _id; + if (_id[0].match(/\d/)) id = 's' + id; if (typeof vertices[id] !== 'undefined') { if (config.securityLevel !== 'loose') { - vertices[id].link = sanitizeUrl(linkStr) // .replace(/javascript:.*/g, '') + vertices[id].link = sanitizeUrl(linkStr); // .replace(/javascript:.*/g, '') } else { - vertices[id].link = linkStr + vertices[id].link = linkStr; } } - }) - setTooltip(ids, tooltip) - setClass(ids, 'clickable') -} -export const getTooltip = function (id) { - return tooltips[id] -} + }); + setTooltip(ids, tooltip); + setClass(ids, 'clickable'); +}; +export const getTooltip = function(id) { + return tooltips[id]; +}; /** * Called by parser when a click definition is found. Registers an event handler. @@ -252,209 +256,219 @@ export const getTooltip = function (id) { * @param functionName Function to be called on click * @param tooltip Tooltip for the clickable element */ -export const setClickEvent = function (ids, functionName, tooltip) { - ids.split(',').forEach(function (id) { setClickFun(id, functionName) }) - setTooltip(ids, tooltip) - setClass(ids, 'clickable') -} +export const setClickEvent = function(ids, functionName, tooltip) { + ids.split(',').forEach(function(id) { + setClickFun(id, functionName); + }); + setTooltip(ids, tooltip); + setClass(ids, 'clickable'); +}; -export const bindFunctions = function (element) { - funs.forEach(function (fun) { - fun(element) - }) -} -export const getDirection = function () { - return direction -} +export const bindFunctions = function(element) { + funs.forEach(function(fun) { + fun(element); + }); +}; +export const getDirection = function() { + return direction; +}; /** * Retrieval function for fetching the found nodes after parsing has completed. * @returns {{}|*|vertices} */ -export const getVertices = function () { - return vertices -} +export const getVertices = function() { + return vertices; +}; /** * Retrieval function for fetching the found links after parsing has completed. * @returns {{}|*|edges} */ -export const getEdges = function () { - return edges -} +export const getEdges = function() { + return edges; +}; /** * Retrieval function for fetching the found class definitions after parsing has completed. * @returns {{}|*|classes} */ -export const getClasses = function () { - return classes -} +export const getClasses = function() { + return classes; +}; -const setupToolTips = function (element) { - let tooltipElem = d3.select('.mermaidTooltip') +const setupToolTips = function(element) { + let tooltipElem = d3.select('.mermaidTooltip'); if ((tooltipElem._groups || tooltipElem)[0][0] === null) { - tooltipElem = d3.select('body') + tooltipElem = d3 + .select('body') .append('div') .attr('class', 'mermaidTooltip') - .style('opacity', 0) + .style('opacity', 0); } - const svg = d3.select(element).select('svg') + const svg = d3.select(element).select('svg'); - const nodes = svg.selectAll('g.node') + const nodes = svg.selectAll('g.node'); nodes - .on('mouseover', function () { - const el = d3.select(this) - const title = el.attr('title') + .on('mouseover', function() { + const el = d3.select(this); + const title = el.attr('title'); // Dont try to draw a tooltip if no data is provided if (title === null) { - return + return; } - const rect = this.getBoundingClientRect() + const rect = this.getBoundingClientRect(); - tooltipElem.transition() + tooltipElem + .transition() .duration(200) - .style('opacity', '.9') - tooltipElem.html(el.attr('title')) - .style('left', (rect.left + (rect.right - rect.left) / 2) + 'px') - .style('top', (rect.top - 14 + document.body.scrollTop) + 'px') - el.classed('hover', true) + .style('opacity', '.9'); + tooltipElem + .html(el.attr('title')) + .style('left', rect.left + (rect.right - rect.left) / 2 + 'px') + .style('top', rect.top - 14 + document.body.scrollTop + 'px'); + el.classed('hover', true); }) - .on('mouseout', function () { - tooltipElem.transition() + .on('mouseout', function() { + tooltipElem + .transition() .duration(500) - .style('opacity', 0) - const el = d3.select(this) - el.classed('hover', false) - }) -} -funs.push(setupToolTips) + .style('opacity', 0); + const el = d3.select(this); + el.classed('hover', false); + }); +}; +funs.push(setupToolTips); /** * Clears the internal graph db so that a new graph can be parsed. */ -export const clear = function () { - vertices = {} - classes = {} - edges = [] - funs = [] - funs.push(setupToolTips) - subGraphs = [] - subGraphLookup = {} - subCount = 0 - tooltips = [] -} +export const clear = function() { + vertices = {}; + classes = {}; + edges = []; + funs = []; + funs.push(setupToolTips); + subGraphs = []; + subGraphLookup = {}; + subCount = 0; + tooltips = []; +}; /** * * @returns {string} */ -export const defaultStyle = function () { - return 'fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;' -} +export const defaultStyle = function() { + return 'fill:#ffa;stroke: #f66; stroke-width: 3px; stroke-dasharray: 5, 5;fill:#ffa;stroke: #666;'; +}; /** * Clears the internal graph db so that a new graph can be parsed. */ -export const addSubGraph = function (_id, list, _title) { - let id = _id - let title = _title +export const addSubGraph = function(_id, list, _title) { + let id = _id; + let title = _title; if (_id === _title && _title.match(/\s/)) { - id = undefined + id = undefined; } - function uniq (a) { - const prims = { 'boolean': {}, 'number': {}, 'string': {} } - const objs = [] + function uniq(a) { + const prims = { boolean: {}, number: {}, string: {} }; + const objs = []; - return a.filter(function (item) { - const type = typeof item + return a.filter(function(item) { + const type = typeof item; if (item.trim() === '') { - return false + return false; } - if (type in prims) { return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true) } else { return objs.indexOf(item) >= 0 ? false : objs.push(item) } - }) + if (type in prims) { + return prims[type].hasOwnProperty(item) ? false : (prims[type][item] = true); + } else { + return objs.indexOf(item) >= 0 ? false : objs.push(item); + } + }); } - let nodeList = [] + let nodeList = []; - nodeList = uniq(nodeList.concat.apply(nodeList, list)) + nodeList = uniq(nodeList.concat.apply(nodeList, list)); for (let i = 0; i < nodeList.length; i++) { - if (nodeList[i][0].match(/\d/)) nodeList[i] = 's' + nodeList[i] + if (nodeList[i][0].match(/\d/)) nodeList[i] = 's' + nodeList[i]; } - id = id || ('subGraph' + subCount) - if (id[0].match(/\d/)) id = 's' + id - title = title || '' - title = sanitize(title) - subCount = subCount + 1 - const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [] } - subGraphs.push(subGraph) - subGraphLookup[id] = subGraph - return id -} + id = id || 'subGraph' + subCount; + if (id[0].match(/\d/)) id = 's' + id; + title = title || ''; + title = sanitize(title); + subCount = subCount + 1; + const subGraph = { id: id, nodes: nodeList, title: title.trim(), classes: [] }; + subGraphs.push(subGraph); + subGraphLookup[id] = subGraph; + return id; +}; -const getPosForId = function (id) { +const getPosForId = function(id) { for (let i = 0; i < subGraphs.length; i++) { if (subGraphs[i].id === id) { - return i + return i; } } - return -1 -} -let secCount = -1 -const posCrossRef = [] -const indexNodes2 = function (id, pos) { - const nodes = subGraphs[pos].nodes - secCount = secCount + 1 + return -1; +}; +let secCount = -1; +const posCrossRef = []; +const indexNodes2 = function(id, pos) { + const nodes = subGraphs[pos].nodes; + secCount = secCount + 1; if (secCount > 2000) { - return + return; } - posCrossRef[secCount] = pos + posCrossRef[secCount] = pos; // Check if match if (subGraphs[pos].id === id) { return { result: true, count: 0 - } + }; } - let count = 0 - let posCount = 1 + let count = 0; + let posCount = 1; while (count < nodes.length) { - const childPos = getPosForId(nodes[count]) + const childPos = getPosForId(nodes[count]); // Ignore regular nodes (pos will be -1) if (childPos >= 0) { - const res = indexNodes2(id, childPos) + const res = indexNodes2(id, childPos); if (res.result) { return { result: true, count: posCount + res.count - } + }; } else { - posCount = posCount + res.count + posCount = posCount + res.count; } } - count = count + 1 + count = count + 1; } return { result: false, count: posCount - } -} + }; +}; -export const getDepthFirstPos = function (pos) { - return posCrossRef[pos] -} -export const indexNodes = function () { - secCount = -1 +export const getDepthFirstPos = function(pos) { + return posCrossRef[pos]; +}; +export const indexNodes = function() { + secCount = -1; if (subGraphs.length > 0) { - indexNodes2('none', subGraphs.length - 1, 0) + indexNodes2('none', subGraphs.length - 1, 0); } -} +}; -export const getSubGraphs = function () { - return subGraphs -} +export const getSubGraphs = function() { + return subGraphs; +}; export default { addVertex, @@ -478,4 +492,4 @@ export default { getDepthFirstPos, indexNodes, getSubGraphs -} +}; diff --git a/src/diagrams/flowchart/flowRenderer.js b/src/diagrams/flowchart/flowRenderer.js index 3df7a6ad9..ef696a8f7 100644 --- a/src/diagrams/flowchart/flowRenderer.js +++ b/src/diagrams/flowchart/flowRenderer.js @@ -1,274 +1,288 @@ -import graphlib from 'graphlibrary' -import * as d3 from 'd3' +import graphlib from 'graphlibrary'; +import * as d3 from 'd3'; -import flowDb from './flowDb' -import flow from './parser/flow' -import { getConfig } from '../../config' -import dagreD3 from 'dagre-d3-renderer' -import addHtmlLabel from 'dagre-d3-renderer/lib/label/add-html-label.js' -import { logger } from '../../logger' -import { interpolateToCurve } from '../../utils' +import flowDb from './flowDb'; +import flow from './parser/flow'; +import { getConfig } from '../../config'; +import dagreD3 from 'dagre-d3-renderer'; +import addHtmlLabel from 'dagre-d3-renderer/lib/label/add-html-label.js'; +import { logger } from '../../logger'; +import { interpolateToCurve } from '../../utils'; -const conf = { -} -export const setConf = function (cnf) { - const keys = Object.keys(cnf) +const conf = {}; +export const setConf = function(cnf) { + const keys = Object.keys(cnf); for (let i = 0; i < keys.length; i++) { - conf[keys[i]] = cnf[keys[i]] + conf[keys[i]] = cnf[keys[i]]; } -} +}; /** * Function that adds the vertices found in the graph definition to the graph to be rendered. * @param vert Object containing the vertices. * @param g The graph that is to be drawn. */ -export const addVertices = function (vert, g, svgId) { - const svg = d3.select(`[id="${svgId}"]`) - const keys = Object.keys(vert) +export const addVertices = function(vert, g, svgId) { + const svg = d3.select(`[id="${svgId}"]`); + const keys = Object.keys(vert); - const styleFromStyleArr = function (styleStr, arr, { label }) { + const styleFromStyleArr = function(styleStr, arr, { label }) { if (!label) { - // Create a compound style definition from the style definitions found for the node in the graph definition + // Create a compound style definition from the style definitions found for the node in the graph definition for (let i = 0; i < arr.length; i++) { if (typeof arr[i] !== 'undefined') { - styleStr = styleStr + arr[i] + ';' + styleStr = styleStr + arr[i] + ';'; } } } else { for (let i = 0; i < arr.length; i++) { if (typeof arr[i] !== 'undefined') { - if (arr[i].match('^color:')) styleStr = styleStr + arr[i] + ';' + if (arr[i].match('^color:')) styleStr = styleStr + arr[i] + ';'; } } } - return styleStr - } + return styleStr; + }; // Iterate through each item in the vertex object (containing all the vertices found) in the graph definition - keys.forEach(function (id) { - const vertex = vert[id] + keys.forEach(function(id) { + const vertex = vert[id]; /** * Variable for storing the classes for the vertex * @type {string} */ - let classStr = '' + let classStr = ''; if (vertex.classes.length > 0) { - classStr = vertex.classes.join(' ') + classStr = vertex.classes.join(' '); } /** * Variable for storing the extracted style for the vertex * @type {string} */ - let style = '' + let style = ''; // Create a compound style definition from the style definitions found for the node in the graph definition - style = styleFromStyleArr(style, vertex.styles, { label: false }) - let labelStyle = '' - labelStyle = styleFromStyleArr(labelStyle, vertex.styles, { label: true }) + style = styleFromStyleArr(style, vertex.styles, { label: false }); + let labelStyle = ''; + labelStyle = styleFromStyleArr(labelStyle, vertex.styles, { label: true }); // Use vertex id as text in the box if no text is provided by the graph definition - let vertexText = vertex.text !== undefined ? vertex.text : vertex.id + let vertexText = vertex.text !== undefined ? vertex.text : vertex.id; // We create a SVG label, either by delegating to addHtmlLabel or manually - let vertexNode + let vertexNode; if (getConfig().flowchart.htmlLabels) { // TODO: addHtmlLabel accepts a labelStyle. Do we possibly have that? - const node = { label: vertexText.replace(/fa[lrsb]?:fa-[\w-]+/g, s => ``) } - vertexNode = addHtmlLabel(svg, node).node() - vertexNode.parentNode.removeChild(vertexNode) + const node = { + label: vertexText.replace( + /fa[lrsb]?:fa-[\w-]+/g, + s => `` + ) + }; + vertexNode = addHtmlLabel(svg, node).node(); + vertexNode.parentNode.removeChild(vertexNode); } else { - const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text') + const svgLabel = document.createElementNS('http://www.w3.org/2000/svg', 'text'); - const rows = vertexText.split(//) + const rows = vertexText.split(//); for (let j = 0; j < rows.length; j++) { - const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan') - tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve') - tspan.setAttribute('dy', '1em') - tspan.setAttribute('x', '1') - tspan.textContent = rows[j] - svgLabel.appendChild(tspan) + const tspan = document.createElementNS('http://www.w3.org/2000/svg', 'tspan'); + tspan.setAttributeNS('http://www.w3.org/XML/1998/namespace', 'xml:space', 'preserve'); + tspan.setAttribute('dy', '1em'); + tspan.setAttribute('x', '1'); + tspan.textContent = rows[j]; + svgLabel.appendChild(tspan); } - vertexNode = svgLabel + vertexNode = svgLabel; } // If the node has a link, we wrap it in a SVG link if (vertex.link) { - const link = document.createElementNS('http://www.w3.org/2000/svg', 'a') - link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link) - link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener') - link.appendChild(vertexNode) - vertexNode = link + const link = document.createElementNS('http://www.w3.org/2000/svg', 'a'); + link.setAttributeNS('http://www.w3.org/2000/svg', 'href', vertex.link); + link.setAttributeNS('http://www.w3.org/2000/svg', 'rel', 'noopener'); + link.appendChild(vertexNode); + vertexNode = link; } - let radious = 0 - let _shape = '' + let radious = 0; + let _shape = ''; // Set the shape based parameters switch (vertex.type) { case 'round': - radious = 5 - _shape = 'rect' - break + radious = 5; + _shape = 'rect'; + break; case 'square': - _shape = 'rect' - break + _shape = 'rect'; + break; case 'diamond': - _shape = 'question' - break + _shape = 'question'; + break; case 'odd': - _shape = 'rect_left_inv_arrow' - break + _shape = 'rect_left_inv_arrow'; + break; case 'lean_right': - _shape = 'lean_right' - break + _shape = 'lean_right'; + break; case 'lean_left': - _shape = 'lean_left' - break + _shape = 'lean_left'; + break; case 'trapezoid': - _shape = 'trapezoid' - break + _shape = 'trapezoid'; + break; case 'inv_trapezoid': - _shape = 'inv_trapezoid' - break + _shape = 'inv_trapezoid'; + break; case 'odd_right': - _shape = 'rect_left_inv_arrow' - break + _shape = 'rect_left_inv_arrow'; + break; case 'circle': - _shape = 'circle' - break + _shape = 'circle'; + break; case 'ellipse': - _shape = 'ellipse' - break + _shape = 'ellipse'; + break; case 'group': - _shape = 'rect' - break + _shape = 'rect'; + break; default: - _shape = 'rect' + _shape = 'rect'; } // Add the node - g.setNode(vertex.id, { labelType: 'svg', labelStyle: labelStyle, shape: _shape, label: vertexNode, rx: radious, ry: radious, 'class': classStr, style: style, id: vertex.id }) - }) -} + g.setNode(vertex.id, { + labelType: 'svg', + labelStyle: labelStyle, + shape: _shape, + label: vertexNode, + rx: radious, + ry: radious, + class: classStr, + style: style, + id: vertex.id + }); + }); +}; /** * Add edges to graph based on parsed graph defninition * @param {Object} edges The edges to add to the graph * @param {Object} g The graph object */ -export const addEdges = function (edges, g) { - let cnt = 0 +export const addEdges = function(edges, g) { + let cnt = 0; - let defaultStyle + let defaultStyle; if (typeof edges.defaultStyle !== 'undefined') { - defaultStyle = edges.defaultStyle.toString().replace(/,/g, ';') + defaultStyle = edges.defaultStyle.toString().replace(/,/g, ';'); } - edges.forEach(function (edge) { - cnt++ - const edgeData = {} + edges.forEach(function(edge) { + cnt++; + const edgeData = {}; // Set link type for rendering if (edge.type === 'arrow_open') { - edgeData.arrowhead = 'none' + edgeData.arrowhead = 'none'; } else { - edgeData.arrowhead = 'normal' + edgeData.arrowhead = 'normal'; } - let style = '' + let style = ''; if (typeof edge.style !== 'undefined') { - edge.style.forEach(function (s) { - style = style + s + ';' - }) + edge.style.forEach(function(s) { + style = style + s + ';'; + }); } else { switch (edge.stroke) { case 'normal': - style = 'fill:none' + style = 'fill:none'; if (typeof defaultStyle !== 'undefined') { - style = defaultStyle + style = defaultStyle; } - break + break; case 'dotted': - style = 'stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;' - break + style = 'stroke: #333; fill:none;stroke-width:2px;stroke-dasharray:3;'; + break; case 'thick': - style = 'stroke: #333; stroke-width: 3.5px;fill:none' - break + style = 'stroke: #333; stroke-width: 3.5px;fill:none'; + break; } } - edgeData.style = style + edgeData.style = style; if (typeof edge.interpolate !== 'undefined') { - edgeData.curve = interpolateToCurve(edge.interpolate, d3.curveLinear) + edgeData.curve = interpolateToCurve(edge.interpolate, d3.curveLinear); } else if (typeof edges.defaultInterpolate !== 'undefined') { - edgeData.curve = interpolateToCurve(edges.defaultInterpolate, d3.curveLinear) + edgeData.curve = interpolateToCurve(edges.defaultInterpolate, d3.curveLinear); } else { - edgeData.curve = interpolateToCurve(conf.curve, d3.curveLinear) + edgeData.curve = interpolateToCurve(conf.curve, d3.curveLinear); } if (typeof edge.text === 'undefined') { if (typeof edge.style !== 'undefined') { - edgeData.arrowheadStyle = 'fill: #333' + edgeData.arrowheadStyle = 'fill: #333'; } } else { - edgeData.arrowheadStyle = 'fill: #333' + edgeData.arrowheadStyle = 'fill: #333'; if (typeof edge.style === 'undefined') { - edgeData.labelpos = 'c' + edgeData.labelpos = 'c'; if (getConfig().flowchart.htmlLabels) { - edgeData.labelType = 'html' - edgeData.label = '' + edge.text + '' + edgeData.labelType = 'html'; + edgeData.label = '' + edge.text + ''; } else { - edgeData.labelType = 'text' - edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none' - edgeData.label = edge.text.replace(/
/g, '\n') + edgeData.labelType = 'text'; + edgeData.style = edgeData.style || 'stroke: #333; stroke-width: 1.5px;fill:none'; + edgeData.label = edge.text.replace(/
/g, '\n'); } } else { - edgeData.label = edge.text.replace(/
/g, '\n') + edgeData.label = edge.text.replace(/
/g, '\n'); } } // Add the edge to the graph - g.setEdge(edge.start, edge.end, edgeData, cnt) - }) -} + g.setEdge(edge.start, edge.end, edgeData, cnt); + }); +}; /** * Returns the all the styles from classDef statements in the graph definition. * @returns {object} classDef styles */ -export const getClasses = function (text) { - logger.info('Extracting classes') - flowDb.clear() - const parser = flow.parser - parser.yy = flowDb +export const getClasses = function(text) { + logger.info('Extracting classes'); + flowDb.clear(); + const parser = flow.parser; + parser.yy = flowDb; // Parse the graph definition - parser.parse(text) - return flowDb.getClasses() -} + parser.parse(text); + return flowDb.getClasses(); +}; /** * Draws a flowchart in the tag with id: id based on the graph definition in text. * @param text * @param id */ -export const draw = function (text, id) { - logger.info('Drawing flowchart') - flowDb.clear() - const parser = flow.parser - parser.yy = flowDb +export const draw = function(text, id) { + logger.info('Drawing flowchart'); + flowDb.clear(); + const parser = flow.parser; + parser.yy = flowDb; // Parse the graph definition try { - parser.parse(text) + parser.parse(text); } catch (err) { - logger.debug('Parsing failed') + logger.debug('Parsing failed'); } // Fetch the default direction, use TD if none was found - let dir = flowDb.getDirection() + let dir = flowDb.getDirection(); if (typeof dir === 'undefined') { - dir = 'TD' + dir = 'TD'; } // Create the input mermaid.graph @@ -280,196 +294,238 @@ export const draw = function (text, id) { rankdir: dir, marginx: 20, marginy: 20 - - }) - .setDefaultEdgeLabel(function () { - return {} }) + .setDefaultEdgeLabel(function() { + return {}; + }); - let subG - const subGraphs = flowDb.getSubGraphs() + let subG; + const subGraphs = flowDb.getSubGraphs(); for (let i = subGraphs.length - 1; i >= 0; i--) { - subG = subGraphs[i] - flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes) + subG = subGraphs[i]; + flowDb.addVertex(subG.id, subG.title, 'group', undefined, subG.classes); } // Fetch the verices/nodes and edges/links from the parsed graph definition - const vert = flowDb.getVertices() + const vert = flowDb.getVertices(); - const edges = flowDb.getEdges() + const edges = flowDb.getEdges(); - let i = 0 + let i = 0; for (i = subGraphs.length - 1; i >= 0; i--) { - subG = subGraphs[i] + subG = subGraphs[i]; - d3.selectAll('cluster').append('text') + d3.selectAll('cluster').append('text'); for (let j = 0; j < subG.nodes.length; j++) { - g.setParent(subG.nodes[j], subG.id) + g.setParent(subG.nodes[j], subG.id); } } - addVertices(vert, g, id) - addEdges(edges, g) + addVertices(vert, g, id); + addEdges(edges, g); // Create the renderer - const Render = dagreD3.render - const render = new Render() + const Render = dagreD3.render; + const render = new Render(); // Add custom shape for rhombus type of boc (decision) - render.shapes().question = function (parent, bbox, node) { - const w = bbox.width - const h = bbox.height - const s = (w + h) * 0.9 + render.shapes().question = function(parent, bbox, node) { + const w = bbox.width; + const h = bbox.height; + const s = (w + h) * 0.9; const points = [ { x: s / 2, y: 0 }, { x: s, y: -s / 2 }, { x: s / 2, y: -s }, { x: 0, y: -s / 2 } - ] - const shapeSvg = parent.insert('polygon', ':first-child') - .attr('points', points.map(function (d) { - return d.x + ',' + d.y - }).join(' ')) + ]; + const shapeSvg = parent + .insert('polygon', ':first-child') + .attr( + 'points', + points + .map(function(d) { + return d.x + ',' + d.y; + }) + .join(' ') + ) .attr('rx', 5) .attr('ry', 5) - .attr('transform', 'translate(' + (-s / 2) + ',' + (s * 2 / 4) + ')') - node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point) - } - return shapeSvg - } + .attr('transform', 'translate(' + -s / 2 + ',' + (s * 2) / 4 + ')'); + node.intersect = function(point) { + return dagreD3.intersect.polygon(node, points, point); + }; + return shapeSvg; + }; // Add custom shape for box with inverted arrow on left side - render.shapes().rect_left_inv_arrow = function (parent, bbox, node) { - const w = bbox.width - const h = bbox.height + render.shapes().rect_left_inv_arrow = function(parent, bbox, node) { + const w = bbox.width; + const h = bbox.height; const points = [ { x: -h / 2, y: 0 }, { x: w, y: 0 }, { x: w, y: -h }, { x: -h / 2, y: -h }, { x: 0, y: -h / 2 } - ] - const shapeSvg = parent.insert('polygon', ':first-child') - .attr('points', points.map(function (d) { - return d.x + ',' + d.y - }).join(' ')) - .attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')') - node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point) - } - return shapeSvg - } + ]; + const shapeSvg = parent + .insert('polygon', ':first-child') + .attr( + 'points', + points + .map(function(d) { + return d.x + ',' + d.y; + }) + .join(' ') + ) + .attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')'); + node.intersect = function(point) { + return dagreD3.intersect.polygon(node, points, point); + }; + return shapeSvg; + }; // Add custom shape for box with inverted arrow on left side - render.shapes().lean_right = function (parent, bbox, node) { - const w = bbox.width - const h = bbox.height + render.shapes().lean_right = function(parent, bbox, node) { + const w = bbox.width; + const h = bbox.height; const points = [ - { x: -2 * h / 6, y: 0 }, + { x: (-2 * h) / 6, y: 0 }, { x: w - h / 6, y: 0 }, - { x: w + 2 * h / 6, y: -h }, + { x: w + (2 * h) / 6, y: -h }, { x: h / 6, y: -h } - ] - const shapeSvg = parent.insert('polygon', ':first-child') - .attr('points', points.map(function (d) { - return d.x + ',' + d.y - }).join(' ')) - .attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')') - node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point) - } - return shapeSvg - } + ]; + const shapeSvg = parent + .insert('polygon', ':first-child') + .attr( + 'points', + points + .map(function(d) { + return d.x + ',' + d.y; + }) + .join(' ') + ) + .attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')'); + node.intersect = function(point) { + return dagreD3.intersect.polygon(node, points, point); + }; + return shapeSvg; + }; // Add custom shape for box with inverted arrow on left side - render.shapes().lean_left = function (parent, bbox, node) { - const w = bbox.width - const h = bbox.height + render.shapes().lean_left = function(parent, bbox, node) { + const w = bbox.width; + const h = bbox.height; const points = [ - { x: 2 * h / 6, y: 0 }, + { x: (2 * h) / 6, y: 0 }, { x: w + h / 6, y: 0 }, - { x: w - 2 * h / 6, y: -h }, + { x: w - (2 * h) / 6, y: -h }, { x: -h / 6, y: -h } - ] - const shapeSvg = parent.insert('polygon', ':first-child') - .attr('points', points.map(function (d) { - return d.x + ',' + d.y - }).join(' ')) - .attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')') - node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point) - } - return shapeSvg - } + ]; + const shapeSvg = parent + .insert('polygon', ':first-child') + .attr( + 'points', + points + .map(function(d) { + return d.x + ',' + d.y; + }) + .join(' ') + ) + .attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')'); + node.intersect = function(point) { + return dagreD3.intersect.polygon(node, points, point); + }; + return shapeSvg; + }; // Add custom shape for box with inverted arrow on left side - render.shapes().trapezoid = function (parent, bbox, node) { - const w = bbox.width - const h = bbox.height + render.shapes().trapezoid = function(parent, bbox, node) { + const w = bbox.width; + const h = bbox.height; const points = [ - { x: -2 * h / 6, y: 0 }, - { x: w + 2 * h / 6, y: 0 }, + { x: (-2 * h) / 6, y: 0 }, + { x: w + (2 * h) / 6, y: 0 }, { x: w - h / 6, y: -h }, { x: h / 6, y: -h } - ] - const shapeSvg = parent.insert('polygon', ':first-child') - .attr('points', points.map(function (d) { - return d.x + ',' + d.y - }).join(' ')) - .attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')') - node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point) - } - return shapeSvg - } + ]; + const shapeSvg = parent + .insert('polygon', ':first-child') + .attr( + 'points', + points + .map(function(d) { + return d.x + ',' + d.y; + }) + .join(' ') + ) + .attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')'); + node.intersect = function(point) { + return dagreD3.intersect.polygon(node, points, point); + }; + return shapeSvg; + }; // Add custom shape for box with inverted arrow on left side - render.shapes().inv_trapezoid = function (parent, bbox, node) { - const w = bbox.width - const h = bbox.height + render.shapes().inv_trapezoid = function(parent, bbox, node) { + const w = bbox.width; + const h = bbox.height; const points = [ { x: h / 6, y: 0 }, { x: w - h / 6, y: 0 }, - { x: w + 2 * h / 6, y: -h }, - { x: -2 * h / 6, y: -h } - ] - const shapeSvg = parent.insert('polygon', ':first-child') - .attr('points', points.map(function (d) { - return d.x + ',' + d.y - }).join(' ')) - .attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')') - node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point) - } - return shapeSvg - } + { x: w + (2 * h) / 6, y: -h }, + { x: (-2 * h) / 6, y: -h } + ]; + const shapeSvg = parent + .insert('polygon', ':first-child') + .attr( + 'points', + points + .map(function(d) { + return d.x + ',' + d.y; + }) + .join(' ') + ) + .attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')'); + node.intersect = function(point) { + return dagreD3.intersect.polygon(node, points, point); + }; + return shapeSvg; + }; // Add custom shape for box with inverted arrow on right side - render.shapes().rect_right_inv_arrow = function (parent, bbox, node) { - const w = bbox.width - const h = bbox.height + render.shapes().rect_right_inv_arrow = function(parent, bbox, node) { + const w = bbox.width; + const h = bbox.height; const points = [ { x: 0, y: 0 }, { x: w + h / 2, y: 0 }, { x: w, y: -h / 2 }, { x: w + h / 2, y: -h }, { x: 0, y: -h } - ] - const shapeSvg = parent.insert('polygon', ':first-child') - .attr('points', points.map(function (d) { - return d.x + ',' + d.y - }).join(' ')) - .attr('transform', 'translate(' + (-w / 2) + ',' + (h * 2 / 4) + ')') - node.intersect = function (point) { - return dagreD3.intersect.polygon(node, points, point) - } - return shapeSvg - } + ]; + const shapeSvg = parent + .insert('polygon', ':first-child') + .attr( + 'points', + points + .map(function(d) { + return d.x + ',' + d.y; + }) + .join(' ') + ) + .attr('transform', 'translate(' + -w / 2 + ',' + (h * 2) / 4 + ')'); + node.intersect = function(point) { + return dagreD3.intersect.polygon(node, points, point); + }; + return shapeSvg; + }; // Add our custom arrow - an empty arrowhead - render.arrows().none = function normal (parent, id, edge, type) { - const marker = parent.append('marker') + render.arrows().none = function normal(parent, id, edge, type) { + const marker = parent + .append('marker') .attr('id', id) .attr('viewBox', '0 0 10 10') .attr('refX', 9) @@ -477,16 +533,16 @@ export const draw = function (text, id) { .attr('markerUnits', 'strokeWidth') .attr('markerWidth', 8) .attr('markerHeight', 6) - .attr('orient', 'auto') + .attr('orient', 'auto'); - const path = marker.append('path') - .attr('d', 'M 0 0 L 0 0 L 0 0 z') - dagreD3.util.applyStyle(path, edge[type + 'Style']) - } + const path = marker.append('path').attr('d', 'M 0 0 L 0 0 L 0 0 z'); + dagreD3.util.applyStyle(path, edge[type + 'Style']); + }; // Override normal arrowhead defined in d3. Remove style & add class to allow css styling. - render.arrows().normal = function normal (parent, id, edge, type) { - const marker = parent.append('marker') + render.arrows().normal = function normal(parent, id, edge, type) { + const marker = parent + .append('marker') .attr('id', id) .attr('viewBox', '0 0 10 10') .attr('refX', 9) @@ -494,76 +550,76 @@ export const draw = function (text, id) { .attr('markerUnits', 'strokeWidth') .attr('markerWidth', 8) .attr('markerHeight', 6) - .attr('orient', 'auto') + .attr('orient', 'auto'); - marker.append('path') + marker + .append('path') .attr('d', 'M 0 0 L 10 5 L 0 10 z') .attr('class', 'arrowheadPath') .style('stroke-width', 1) - .style('stroke-dasharray', '1,0') - } + .style('stroke-dasharray', '1,0'); + }; // Set up an SVG group so that we can translate the final graph. - const svg = d3.select(`[id="${id}"]`) + const svg = d3.select(`[id="${id}"]`); // Run the renderer. This is what draws the final graph. - const element = d3.select('#' + id + ' g') - render(element, g) + const element = d3.select('#' + id + ' g'); + render(element, g); - element.selectAll('g.node') - .attr('title', function () { - return flowDb.getTooltip(this.id) - }) + element.selectAll('g.node').attr('title', function() { + return flowDb.getTooltip(this.id); + }); - const padding = 8 - const width = g.maxX - g.minX + padding * 2 - const height = g.maxY - g.minY + padding * 2 - svg.attr('width', '100%') - svg.attr('style', `max-width: ${width}px;`) - svg.attr('viewBox', `0 0 ${width} ${height}`) - svg.select('g').attr('transform', `translate(${padding - g.minX}, ${padding - g.minY})`) + const padding = 8; + const width = g.maxX - g.minX + padding * 2; + const height = g.maxY - g.minY + padding * 2; + svg.attr('width', '100%'); + svg.attr('style', `max-width: ${width}px;`); + svg.attr('viewBox', `0 0 ${width} ${height}`); + svg.select('g').attr('transform', `translate(${padding - g.minX}, ${padding - g.minY})`); // Index nodes - flowDb.indexNodes('subGraph' + i) + flowDb.indexNodes('subGraph' + i); // reposition labels for (i = 0; i < subGraphs.length; i++) { - subG = subGraphs[i] + subG = subGraphs[i]; if (subG.title !== 'undefined') { - const clusterRects = document.querySelectorAll('#' + id + ' #' + subG.id + ' rect') - const clusterEl = document.querySelectorAll('#' + id + ' #' + subG.id) + const clusterRects = document.querySelectorAll('#' + id + ' #' + subG.id + ' rect'); + const clusterEl = document.querySelectorAll('#' + id + ' #' + subG.id); - const xPos = clusterRects[0].x.baseVal.value - const yPos = clusterRects[0].y.baseVal.value - const width = clusterRects[0].width.baseVal.value - const cluster = d3.select(clusterEl[0]) - const te = cluster.select('.label') - te.attr('transform', `translate(${xPos + width / 2}, ${yPos + 14})`) - te.attr('id', id + 'Text') + const xPos = clusterRects[0].x.baseVal.value; + const yPos = clusterRects[0].y.baseVal.value; + const width = clusterRects[0].width.baseVal.value; + const cluster = d3.select(clusterEl[0]); + const te = cluster.select('.label'); + te.attr('transform', `translate(${xPos + width / 2}, ${yPos + 14})`); + te.attr('id', id + 'Text'); } } // Add label rects for non html labels if (!getConfig().flowchart.htmlLabels) { - const labels = document.querySelectorAll('#' + id + ' .edgeLabel .label') + const labels = document.querySelectorAll('#' + id + ' .edgeLabel .label'); for (let k = 0; k < labels.length; k++) { - const label = labels[k] + const label = labels[k]; // Get dimensions of label - const dim = label.getBBox() + const dim = label.getBBox(); - const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect') - rect.setAttribute('rx', 0) - rect.setAttribute('ry', 0) - rect.setAttribute('width', dim.width) - rect.setAttribute('height', dim.height) - rect.setAttribute('style', 'fill:#e8e8e8;') + const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); + rect.setAttribute('rx', 0); + rect.setAttribute('ry', 0); + rect.setAttribute('width', dim.width); + rect.setAttribute('height', dim.height); + rect.setAttribute('style', 'fill:#e8e8e8;'); - label.insertBefore(rect, label.firstChild) + label.insertBefore(rect, label.firstChild); } } -} +}; export default { setConf, @@ -571,4 +627,4 @@ export default { addEdges, getClasses, draw -} +}; diff --git a/src/diagrams/flowchart/parser/flow-vertice-chaining.spec.js b/src/diagrams/flowchart/parser/flow-vertice-chaining.spec.js index e2247418c..db8cfadfe 100644 --- a/src/diagrams/flowchart/parser/flow-vertice-chaining.spec.js +++ b/src/diagrams/flowchart/parser/flow-vertice-chaining.spec.js @@ -1,38 +1,37 @@ -import flowDb from '../flowDb' -import flow from './flow' -import { setConfig } from '../../../config' +import flowDb from '../flowDb'; +import flow from './flow'; +import { setConfig } from '../../../config'; setConfig({ - securityLevel: 'strict', -}) + securityLevel: 'strict' +}); -describe('when parsing flowcharts', function () { - beforeEach(function () { - flow.parser.yy = flowDb - flow.parser.yy.clear() - }) +describe('when parsing flowcharts', function() { + beforeEach(function() { + flow.parser.yy = flowDb; + flow.parser.yy.clear(); + }); - it('should handle chaining of vertices', function () { + it('should handle chaining of vertices', function() { const res = flow.parser.parse(` graph TD A-->B-->C; `); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(vert['C'].id).toBe('C') - expect(edges.length).toBe(2) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - expect(edges[1].start).toBe('B') - expect(edges[1].end).toBe('C') - expect(edges[1].type).toBe('arrow') - expect(edges[1].text).toBe('') - }) - -}) + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(vert['C'].id).toBe('C'); + expect(edges.length).toBe(2); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + expect(edges[1].start).toBe('B'); + expect(edges[1].end).toBe('C'); + expect(edges[1].type).toBe('arrow'); + expect(edges[1].text).toBe(''); + }); +}); diff --git a/src/diagrams/flowchart/parser/flow.spec.js b/src/diagrams/flowchart/parser/flow.spec.js index 8cb91f21d..5b99fcc3d 100644 --- a/src/diagrams/flowchart/parser/flow.spec.js +++ b/src/diagrams/flowchart/parser/flow.spec.js @@ -1,361 +1,366 @@ -import flowDb from '../flowDb' -import flow from './flow' -import { setConfig } from '../../../config' +import flowDb from '../flowDb'; +import flow from './flow'; +import { setConfig } from '../../../config'; setConfig({ - securityLevel: 'strict', -}) - -describe('when parsing ', function () { - beforeEach(function () { - flow.parser.yy = flowDb - flow.parser.yy.clear() - }) - - it('should handle a nodes and edges', function () { - const res = flow.parser.parse('graph TD;\nA-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it("should handle angle bracket ' > ' as direction LR", function () { - const res = flow.parser.parse('graph >;A-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - const direction = flow.parser.yy.getDirection() - - expect(direction).toBe('LR') - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it("should handle angle bracket ' < ' as direction RL", function () { - const res = flow.parser.parse('graph <;A-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - const direction = flow.parser.yy.getDirection() - - expect(direction).toBe('RL') - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it("should handle caret ' ^ ' as direction BT", function () { - const res = flow.parser.parse('graph ^;A-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - const direction = flow.parser.yy.getDirection() - - expect(direction).toBe('BT') - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it('should handle lower-case \'v\' as direction TB', function () { - const res = flow.parser.parse('graph v;A-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - const direction = flow.parser.yy.getDirection() - - expect(direction).toBe('TB') - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it('should handle a nodes and edges and a space between link and node', function () { - const res = flow.parser.parse('graph TD;A --> B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it('should handle a nodes and edges, a space between link and node and each line ending without semicolon', function () { - const res = flow.parser.parse('graph TD\nA --> B\n style e red') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - it('should handle statements ending without semicolon', function () { - const res = flow.parser.parse('graph TD\nA-->B\nB-->C') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(2) - expect(edges[1].start).toBe('B') - expect(edges[1].end).toBe('C') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it('should handle a comments', function () { - const res = flow.parser.parse('graph TD;\n%% CComment\n A-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - it('should handle comments a at the start', function () { - const res = flow.parser.parse('%% Comment\ngraph TD;\n A-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - it('should handle comments at the end', function () { - const res = flow.parser.parse('graph TD;\n A-->B\n %% Comment at the find\n') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - it('should handle comments at the end no trailing newline', function () { - const res = flow.parser.parse('graph TD;\n A-->B\n%% Commento') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - it('should handle comments at the end many trailing newlines', function () { - const res = flow.parser.parse('graph TD;\n A-->B\n%% Commento\n\n\n') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - it('should handle no trailing newlines', function () { - const res = flow.parser.parse('graph TD;\n A-->B') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - it('should handle many trailing newlines', function () { - const res = flow.parser.parse('graph TD;\n A-->B\n\n') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - it('should handle a comments with blank rows in-between', function () { - const res = flow.parser.parse('graph TD;\n\n\n %% Comment\n A-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it('should handle a comments mermaid flowchart code in them', function () { - const res = flow.parser.parse('graph TD;\n\n\n %% Test od>Odd shape]-->|Two line
edge comment|ro;\n A-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it('it should handle a trailing whitespaces after statememnts', function () { - const res = flow.parser.parse('graph TD;\n\n\n %% Comment\n A-->B; \n B-->C;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(2) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('') - }) - - it('should handle node names with "end" substring', function () { - const res = flow.parser.parse('graph TD\nendpoint --> sender') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['endpoint'].id).toBe('endpoint') - expect(vert['sender'].id).toBe('sender') - expect(edges[0].start).toBe('endpoint') - expect(edges[0].end).toBe('sender') - }) - - it('should handle node names ending with keywords', function () { - const res = flow.parser.parse('graph TD\nblend --> monograph') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['blend'].id).toBe('blend') - expect(vert['monograph'].id).toBe('monograph') - expect(edges[0].start).toBe('blend') - expect(edges[0].end).toBe('monograph') - }) - - it('should handle open ended edges', function () { - const res = flow.parser.parse('graph TD;A---B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_open') - }) - - it('should handle cross ended edges', function () { - const res = flow.parser.parse('graph TD;A--xB;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - }) - - it('should handle open ended edges', function () { - const res = flow.parser.parse('graph TD;A--oB;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_circle') - }) - it('should handle classDefs with style in classes', function () { - const res = flow.parser.parse('graph TD\nA-->B\nclassDef exClass font-style:bold;') + securityLevel: 'strict' +}); + +describe('when parsing ', function() { + beforeEach(function() { + flow.parser.yy = flowDb; + flow.parser.yy.clear(); + }); + + it('should handle a nodes and edges', function() { + const res = flow.parser.parse('graph TD;\nA-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it("should handle angle bracket ' > ' as direction LR", function() { + const res = flow.parser.parse('graph >;A-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + const direction = flow.parser.yy.getDirection(); + + expect(direction).toBe('LR'); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it("should handle angle bracket ' < ' as direction RL", function() { + const res = flow.parser.parse('graph <;A-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + const direction = flow.parser.yy.getDirection(); + + expect(direction).toBe('RL'); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it("should handle caret ' ^ ' as direction BT", function() { + const res = flow.parser.parse('graph ^;A-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + const direction = flow.parser.yy.getDirection(); + + expect(direction).toBe('BT'); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it("should handle lower-case 'v' as direction TB", function() { + const res = flow.parser.parse('graph v;A-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + const direction = flow.parser.yy.getDirection(); + + expect(direction).toBe('TB'); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it('should handle a nodes and edges and a space between link and node', function() { + const res = flow.parser.parse('graph TD;A --> B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it('should handle a nodes and edges, a space between link and node and each line ending without semicolon', function() { + const res = flow.parser.parse('graph TD\nA --> B\n style e red'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + it('should handle statements ending without semicolon', function() { + const res = flow.parser.parse('graph TD\nA-->B\nB-->C'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(2); + expect(edges[1].start).toBe('B'); + expect(edges[1].end).toBe('C'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it('should handle a comments', function() { + const res = flow.parser.parse('graph TD;\n%% CComment\n A-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + it('should handle comments a at the start', function() { + const res = flow.parser.parse('%% Comment\ngraph TD;\n A-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + it('should handle comments at the end', function() { + const res = flow.parser.parse('graph TD;\n A-->B\n %% Comment at the find\n'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + it('should handle comments at the end no trailing newline', function() { + const res = flow.parser.parse('graph TD;\n A-->B\n%% Commento'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + it('should handle comments at the end many trailing newlines', function() { + const res = flow.parser.parse('graph TD;\n A-->B\n%% Commento\n\n\n'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + it('should handle no trailing newlines', function() { + const res = flow.parser.parse('graph TD;\n A-->B'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + it('should handle many trailing newlines', function() { + const res = flow.parser.parse('graph TD;\n A-->B\n\n'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + it('should handle a comments with blank rows in-between', function() { + const res = flow.parser.parse('graph TD;\n\n\n %% Comment\n A-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it('should handle a comments mermaid flowchart code in them', function() { + const res = flow.parser.parse( + 'graph TD;\n\n\n %% Test od>Odd shape]-->|Two line
edge comment|ro;\n A-->B;' + ); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it('it should handle a trailing whitespaces after statememnts', function() { + const res = flow.parser.parse('graph TD;\n\n\n %% Comment\n A-->B; \n B-->C;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(2); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe(''); + }); + + it('should handle node names with "end" substring', function() { + const res = flow.parser.parse('graph TD\nendpoint --> sender'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['endpoint'].id).toBe('endpoint'); + expect(vert['sender'].id).toBe('sender'); + expect(edges[0].start).toBe('endpoint'); + expect(edges[0].end).toBe('sender'); + }); + + it('should handle node names ending with keywords', function() { + const res = flow.parser.parse('graph TD\nblend --> monograph'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['blend'].id).toBe('blend'); + expect(vert['monograph'].id).toBe('monograph'); + expect(edges[0].start).toBe('blend'); + expect(edges[0].end).toBe('monograph'); + }); + + it('should handle open ended edges', function() { + const res = flow.parser.parse('graph TD;A---B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_open'); + }); + + it('should handle cross ended edges', function() { + const res = flow.parser.parse('graph TD;A--xB;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + }); + + it('should handle open ended edges', function() { + const res = flow.parser.parse('graph TD;A--oB;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_circle'); + }); + it('should handle classDefs with style in classes', function() { + const res = flow.parser.parse('graph TD\nA-->B\nclassDef exClass font-style:bold;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + expect(edges[0].type).toBe('arrow'); + }); - expect(edges[0].type).toBe('arrow') - }) + it('should handle classDefs with % in classes', function() { + const res = flow.parser.parse( + 'graph TD\nA-->B\nclassDef exClass fill:#f96,stroke:#333,stroke-width:4px,font-size:50%,font-style:bold;' + ); - it('should handle classDefs with % in classes', function () { - const res = flow.parser.parse('graph TD\nA-->B\nclassDef exClass fill:#f96,stroke:#333,stroke-width:4px,font-size:50%,font-style:bold;') + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + expect(edges[0].type).toBe('arrow'); + }); - expect(edges[0].type).toBe('arrow') - }) - - it('should handle style definitions with more then 1 digit in a row', function () { - const res = flow.parser.parse('graph TD\n' + + it('should handle style definitions with more then 1 digit in a row', function() { + const res = flow.parser.parse( + 'graph TD\n' + 'A-->B1\n' + 'A-->B2\n' + 'A-->B3\n' + @@ -367,16 +372,18 @@ describe('when parsing ', function () { 'A-->B9\n' + 'A-->B10\n' + 'A-->B11\n' + - 'linkStyle 10 stroke-width:1px;') + 'linkStyle 10 stroke-width:1px;' + ); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow') - }) + expect(edges[0].type).toBe('arrow'); + }); - it('should handle multi-numbered style definitons with more then 1 digit in a row', function () { - const res = flow.parser.parse('graph TD\n' + + it('should handle multi-numbered style definitons with more then 1 digit in a row', function() { + const res = flow.parser.parse( + 'graph TD\n' + 'A-->B1\n' + 'A-->B2\n' + 'A-->B3\n' + @@ -389,1360 +396,1372 @@ describe('when parsing ', function () { 'A-->B10\n' + 'A-->B11\n' + 'A-->B12\n' + - 'linkStyle 10,11 stroke-width:1px;') + 'linkStyle 10,11 stroke-width:1px;' + ); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow') - }) + expect(edges[0].type).toBe('arrow'); + }); - it('should handle line interpolation default definitions', function () { - const res = flow.parser.parse('graph TD\n' + - 'A-->B\n' + - 'linkStyle default interpolate basis') + it('should handle line interpolation default definitions', function() { + const res = flow.parser.parse('graph TD\n' + 'A-->B\n' + 'linkStyle default interpolate basis'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges.defaultInterpolate).toBe('basis') - }) + expect(edges.defaultInterpolate).toBe('basis'); + }); - it('should handle line interpolation numbered definitions', function () { - const res = flow.parser.parse('graph TD\n' + + it('should handle line interpolation numbered definitions', function() { + const res = flow.parser.parse( + 'graph TD\n' + 'A-->B\n' + 'A-->C\n' + 'linkStyle 0 interpolate basis\n' + - 'linkStyle 1 interpolate cardinal') + 'linkStyle 1 interpolate cardinal' + ); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].interpolate).toBe('basis') - expect(edges[1].interpolate).toBe('cardinal') - }) + expect(edges[0].interpolate).toBe('basis'); + expect(edges[1].interpolate).toBe('cardinal'); + }); - it('should handle line interpolation multi-numbered definitions', function () { - const res = flow.parser.parse('graph TD\n' + - 'A-->B\n' + - 'A-->C\n' + - 'linkStyle 0,1 interpolate basis') + it('should handle line interpolation multi-numbered definitions', function() { + const res = flow.parser.parse( + 'graph TD\n' + 'A-->B\n' + 'A-->C\n' + 'linkStyle 0,1 interpolate basis' + ); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].interpolate).toBe('basis') - expect(edges[1].interpolate).toBe('basis') - }) + expect(edges[0].interpolate).toBe('basis'); + expect(edges[1].interpolate).toBe('basis'); + }); - it('should handle line interpolation default with style', function () { - const res = flow.parser.parse('graph TD\n' + - 'A-->B\n' + - 'linkStyle default interpolate basis stroke-width:1px;') + it('should handle line interpolation default with style', function() { + const res = flow.parser.parse( + 'graph TD\n' + 'A-->B\n' + 'linkStyle default interpolate basis stroke-width:1px;' + ); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges.defaultInterpolate).toBe('basis') - }) + expect(edges.defaultInterpolate).toBe('basis'); + }); - it('should handle line interpolation numbered with style', function () { - const res = flow.parser.parse('graph TD\n' + + it('should handle line interpolation numbered with style', function() { + const res = flow.parser.parse( + 'graph TD\n' + 'A-->B\n' + 'A-->C\n' + 'linkStyle 0 interpolate basis stroke-width:1px;\n' + - 'linkStyle 1 interpolate cardinal stroke-width:1px;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].interpolate).toBe('basis') - expect(edges[1].interpolate).toBe('cardinal') - }) - - it('should handle line interpolation multi-numbered with style', function () { - const res = flow.parser.parse('graph TD\n' + - 'A-->B\n' + - 'A-->C\n' + - 'linkStyle 0,1 interpolate basis stroke-width:1px;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].interpolate).toBe('basis') - expect(edges[1].interpolate).toBe('basis') - }) - - describe('it should handle interaction, ', function () { - it('it should be possible to use click to a callback', function () { - spyOn(flowDb, 'setClickEvent') - const res = flow.parser.parse('graph TD\nA-->B\nclick A callback') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(flowDb.setClickEvent).toHaveBeenCalledWith('A', 'callback', undefined) - }) - - it('it should be possible to use click to a callback with toolip', function () { - spyOn(flowDb, 'setClickEvent') - const res = flow.parser.parse('graph TD\nA-->B\nclick A callback "tooltip"') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(flowDb.setClickEvent).toHaveBeenCalledWith('A', 'callback', 'tooltip') - }) - - it('should handle interaction - click to a link', function () { - spyOn(flowDb, 'setLink') - const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html"') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', undefined) - }) - it('should handle interaction - click to a link with tooltip', function () { - spyOn(flowDb, 'setLink') - const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html" "tooltip"') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', 'tooltip') - }) - }) - - describe('it should multi directional arrows', function () { - describe('point', function () { - it('should handle double edged nodes and edges', function () { - const res = flow.parser.parse('graph TD;\nA<-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_point') - expect(edges[0].text).toBe('') - }) - it('should handle double edged nodes with text', function () { - const res = flow.parser.parse('graph TD;\nA<-- text -->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_point') - expect(edges[0].stroke).toBe('normal') - expect(edges[0].text).toBe('text') - }) - it('should handle double edged nodes and edges on thick arrows', function () { - const res = flow.parser.parse('graph TD;\nA<==>B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_point') - expect(edges[0].stroke).toBe('thick') - expect(edges[0].text).toBe('') - }) - it('should handle double edged nodes with text on thick arrows', function () { - const res = flow.parser.parse('graph TD;\nA<== text ==>B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_point') - expect(edges[0].stroke).toBe('thick') - expect(edges[0].text).toBe('text') - }) - it('should handle double edged nodes and edges on dotted arrows', function () { - const res = flow.parser.parse('graph TD;\nA<-.->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_point') - expect(edges[0].stroke).toBe('dotted') - expect(edges[0].text).toBe('') - }) - it('should handle double edged nodes with text on dotted arrows', function () { - const res = flow.parser.parse('graph TD;\nA<-. text .->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_point') - expect(edges[0].stroke).toBe('dotted') - expect(edges[0].text).toBe('text') - }) - }) - describe('cross', function () { - it('should handle double edged nodes and edges', function () { - const res = flow.parser.parse('graph TD;\nA x--x B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_cross') - expect(edges[0].text).toBe('') - }) - it('should handle double edged nodes with text', function () { - const res = flow.parser.parse('graph TD;\nA x-- text --x B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_cross') - expect(edges[0].stroke).toBe('normal') - expect(edges[0].text).toBe('text') - }) - it('should handle double edged nodes and edges on thick arrows', function () { - const res = flow.parser.parse('graph TD;\nA x==x B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_cross') - expect(edges[0].stroke).toBe('thick') - expect(edges[0].text).toBe('') - }) - it('should handle double edged nodes with text on thick arrows', function () { - const res = flow.parser.parse('graph TD;\nA x== text ==x B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_cross') - expect(edges[0].stroke).toBe('thick') - expect(edges[0].text).toBe('text') - }) - it('should handle double edged nodes and edges on dotted arrows', function () { - const res = flow.parser.parse('graph TD;\nA x-.-x B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_cross') - expect(edges[0].stroke).toBe('dotted') - expect(edges[0].text).toBe('') - }) - it('should handle double edged nodes with text on dotted arrows', function () { - const res = flow.parser.parse('graph TD;\nA x-. text .-x B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_cross') - expect(edges[0].stroke).toBe('dotted') - expect(edges[0].text).toBe('text') - }) - }) - describe('circle', function () { - it('should handle double edged nodes and edges', function () { - const res = flow.parser.parse('graph TD;\nA o--o B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_circle') - expect(edges[0].text).toBe('') - }) - it('should handle double edged nodes with text', function () { - const res = flow.parser.parse('graph TD;\nA o-- text --o B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_circle') - expect(edges[0].stroke).toBe('normal') - expect(edges[0].text).toBe('text') - }) - it('should handle double edged nodes and edges on thick arrows', function () { - const res = flow.parser.parse('graph TD;\nA o==o B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_circle') - expect(edges[0].stroke).toBe('thick') - expect(edges[0].text).toBe('') - }) - it('should handle double edged nodes with text on thick arrows', function () { - const res = flow.parser.parse('graph TD;\nA o== text ==o B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_circle') - expect(edges[0].stroke).toBe('thick') - expect(edges[0].text).toBe('text') - }) - it('should handle double edged nodes and edges on dotted arrows', function () { - const res = flow.parser.parse('graph TD;\nA o-.-o B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_circle') - expect(edges[0].stroke).toBe('dotted') - expect(edges[0].text).toBe('') - }) - it('should handle double edged nodes with text on dotted arrows', function () { - const res = flow.parser.parse('graph TD;\nA o-. text .-o B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(1) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].type).toBe('double_arrow_circle') - expect(edges[0].stroke).toBe('dotted') - expect(edges[0].text).toBe('text') - }) - }) - - }) - describe('it should handle text on edges', function () { - it('it should handle text without space', function () { - const res = flow.parser.parse('graph TD;A--x|textNoSpace|B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - }) - - it('should handle with space', function () { - const res = flow.parser.parse('graph TD;A--x|text including space|B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - }) - - it('it should handle text with /', function () { - const res = flow.parser.parse('graph TD;A--x|text with / should work|B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].text).toBe('text with / should work') - }) - - it('it should handle space and space between vertices and link', function () { - const res = flow.parser.parse('graph TD;A --x|textNoSpace| B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - }) - - it('should handle space and CAPS', function () { - const res = flow.parser.parse('graph TD;A--x|text including CAPS space|B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - }) - - it('should handle space and dir', function () { - const res = flow.parser.parse('graph TD;A--x|text including URL space|B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - expect(edges[0].text).toBe('text including URL space') - }) - - it('should handle space and send', function () { - const res = flow.parser.parse('graph TD;A--text including URL space and send-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('text including URL space and send') - }) - it('should handle space and send', function () { - const res = flow.parser.parse('graph TD;A-- text including URL space and send -->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow') - expect(edges[0].text).toBe('text including URL space and send') - }) - - it('should handle space and dir (TD)', function () { - const res = flow.parser.parse('graph TD;A--x|text including R TD space|B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - expect(edges[0].text).toBe('text including R TD space') - }) - it('should handle `', function () { - const res = flow.parser.parse('graph TD;A--x|text including `|B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - expect(edges[0].text).toBe('text including `') - }) - it('should handle v in node ids only v', function () { - // only v - const res = flow.parser.parse('graph TD;A--xv(my text);') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - expect(vert['v'].text).toBe('my text') - }) - it('should handle v in node ids v at end', function () { - // v at end - const res = flow.parser.parse('graph TD;A--xcsv(my text);') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - expect(vert['csv'].text).toBe('my text') - }) - it('should handle v in node ids v in middle', function () { - // v in middle - const res = flow.parser.parse('graph TD;A--xava(my text);') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - expect(vert['ava'].text).toBe('my text') - }) - it('should handle v in node ids, v at start', function () { - // v at start - const res = flow.parser.parse('graph TD;A--xva(my text);') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - expect(vert['va'].text).toBe('my text') - }) - it('should handle keywords', function () { - const res = flow.parser.parse('graph TD;A--x|text including graph space|B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].text).toBe('text including graph space') - }) - it('should handle keywords', function () { - const res = flow.parser.parse('graph TD;V-->a[v]') - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - expect(vert['a'].text).toBe('v') - }) - it('should handle keywords', function () { - const res = flow.parser.parse('graph TD;V-->a[v]') - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - expect(vert['a'].text).toBe('v') - }) - it('should handle quoted text', function () { - const res = flow.parser.parse('graph TD;V-- "test string()" -->a[v]') - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - expect(edges[0].text).toBe('test string()') - }) - }) - - describe('it should handle new line type notation', function () { - it('it should handle regular lines', function () { - const res = flow.parser.parse('graph TD;A-->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].stroke).toBe('normal') - }) - it('it should handle dotted lines', function () { - const res = flow.parser.parse('graph TD;A-.->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].stroke).toBe('dotted') - }) - it('it should handle dotted lines', function () { - const res = flow.parser.parse('graph TD;A==>B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].stroke).toBe('thick') - }) - it('it should handle text on lines', function () { - const res = flow.parser.parse('graph TD;A-- test text with == -->B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].stroke).toBe('normal') - }) - it('it should handle text on lines', function () { - const res = flow.parser.parse('graph TD;A-. test text with == .->B;') + 'linkStyle 1 interpolate cardinal stroke-width:1px;' + ); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].interpolate).toBe('basis'); + expect(edges[1].interpolate).toBe('cardinal'); + }); + + it('should handle line interpolation multi-numbered with style', function() { + const res = flow.parser.parse( + 'graph TD\n' + 'A-->B\n' + 'A-->C\n' + 'linkStyle 0,1 interpolate basis stroke-width:1px;' + ); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].interpolate).toBe('basis'); + expect(edges[1].interpolate).toBe('basis'); + }); + + describe('it should handle interaction, ', function() { + it('it should be possible to use click to a callback', function() { + spyOn(flowDb, 'setClickEvent'); + const res = flow.parser.parse('graph TD\nA-->B\nclick A callback'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(flowDb.setClickEvent).toHaveBeenCalledWith('A', 'callback', undefined); + }); + + it('it should be possible to use click to a callback with toolip', function() { + spyOn(flowDb, 'setClickEvent'); + const res = flow.parser.parse('graph TD\nA-->B\nclick A callback "tooltip"'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(flowDb.setClickEvent).toHaveBeenCalledWith('A', 'callback', 'tooltip'); + }); + + it('should handle interaction - click to a link', function() { + spyOn(flowDb, 'setLink'); + const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html"'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', undefined); + }); + it('should handle interaction - click to a link with tooltip', function() { + spyOn(flowDb, 'setLink'); + const res = flow.parser.parse('graph TD\nA-->B\nclick A "click.html" "tooltip"'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(flowDb.setLink).toHaveBeenCalledWith('A', 'click.html', 'tooltip'); + }); + }); + + describe('it should multi directional arrows', function() { + describe('point', function() { + it('should handle double edged nodes and edges', function() { + const res = flow.parser.parse('graph TD;\nA<-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_point'); + expect(edges[0].text).toBe(''); + }); + it('should handle double edged nodes with text', function() { + const res = flow.parser.parse('graph TD;\nA<-- text -->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_point'); + expect(edges[0].stroke).toBe('normal'); + expect(edges[0].text).toBe('text'); + }); + it('should handle double edged nodes and edges on thick arrows', function() { + const res = flow.parser.parse('graph TD;\nA<==>B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_point'); + expect(edges[0].stroke).toBe('thick'); + expect(edges[0].text).toBe(''); + }); + it('should handle double edged nodes with text on thick arrows', function() { + const res = flow.parser.parse('graph TD;\nA<== text ==>B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_point'); + expect(edges[0].stroke).toBe('thick'); + expect(edges[0].text).toBe('text'); + }); + it('should handle double edged nodes and edges on dotted arrows', function() { + const res = flow.parser.parse('graph TD;\nA<-.->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_point'); + expect(edges[0].stroke).toBe('dotted'); + expect(edges[0].text).toBe(''); + }); + it('should handle double edged nodes with text on dotted arrows', function() { + const res = flow.parser.parse('graph TD;\nA<-. text .->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_point'); + expect(edges[0].stroke).toBe('dotted'); + expect(edges[0].text).toBe('text'); + }); + }); + describe('cross', function() { + it('should handle double edged nodes and edges', function() { + const res = flow.parser.parse('graph TD;\nA x--x B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_cross'); + expect(edges[0].text).toBe(''); + }); + it('should handle double edged nodes with text', function() { + const res = flow.parser.parse('graph TD;\nA x-- text --x B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_cross'); + expect(edges[0].stroke).toBe('normal'); + expect(edges[0].text).toBe('text'); + }); + it('should handle double edged nodes and edges on thick arrows', function() { + const res = flow.parser.parse('graph TD;\nA x==x B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_cross'); + expect(edges[0].stroke).toBe('thick'); + expect(edges[0].text).toBe(''); + }); + it('should handle double edged nodes with text on thick arrows', function() { + const res = flow.parser.parse('graph TD;\nA x== text ==x B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_cross'); + expect(edges[0].stroke).toBe('thick'); + expect(edges[0].text).toBe('text'); + }); + it('should handle double edged nodes and edges on dotted arrows', function() { + const res = flow.parser.parse('graph TD;\nA x-.-x B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_cross'); + expect(edges[0].stroke).toBe('dotted'); + expect(edges[0].text).toBe(''); + }); + it('should handle double edged nodes with text on dotted arrows', function() { + const res = flow.parser.parse('graph TD;\nA x-. text .-x B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_cross'); + expect(edges[0].stroke).toBe('dotted'); + expect(edges[0].text).toBe('text'); + }); + }); + describe('circle', function() { + it('should handle double edged nodes and edges', function() { + const res = flow.parser.parse('graph TD;\nA o--o B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_circle'); + expect(edges[0].text).toBe(''); + }); + it('should handle double edged nodes with text', function() { + const res = flow.parser.parse('graph TD;\nA o-- text --o B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_circle'); + expect(edges[0].stroke).toBe('normal'); + expect(edges[0].text).toBe('text'); + }); + it('should handle double edged nodes and edges on thick arrows', function() { + const res = flow.parser.parse('graph TD;\nA o==o B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_circle'); + expect(edges[0].stroke).toBe('thick'); + expect(edges[0].text).toBe(''); + }); + it('should handle double edged nodes with text on thick arrows', function() { + const res = flow.parser.parse('graph TD;\nA o== text ==o B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_circle'); + expect(edges[0].stroke).toBe('thick'); + expect(edges[0].text).toBe('text'); + }); + it('should handle double edged nodes and edges on dotted arrows', function() { + const res = flow.parser.parse('graph TD;\nA o-.-o B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_circle'); + expect(edges[0].stroke).toBe('dotted'); + expect(edges[0].text).toBe(''); + }); + it('should handle double edged nodes with text on dotted arrows', function() { + const res = flow.parser.parse('graph TD;\nA o-. text .-o B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(1); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].type).toBe('double_arrow_circle'); + expect(edges[0].stroke).toBe('dotted'); + expect(edges[0].text).toBe('text'); + }); + }); + }); + describe('it should handle text on edges', function() { + it('it should handle text without space', function() { + const res = flow.parser.parse('graph TD;A--x|textNoSpace|B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + }); + + it('should handle with space', function() { + const res = flow.parser.parse('graph TD;A--x|text including space|B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + }); + + it('it should handle text with /', function() { + const res = flow.parser.parse('graph TD;A--x|text with / should work|B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].text).toBe('text with / should work'); + }); + + it('it should handle space and space between vertices and link', function() { + const res = flow.parser.parse('graph TD;A --x|textNoSpace| B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + }); + + it('should handle space and CAPS', function() { + const res = flow.parser.parse('graph TD;A--x|text including CAPS space|B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + }); + + it('should handle space and dir', function() { + const res = flow.parser.parse('graph TD;A--x|text including URL space|B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + expect(edges[0].text).toBe('text including URL space'); + }); + + it('should handle space and send', function() { + const res = flow.parser.parse('graph TD;A--text including URL space and send-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe('text including URL space and send'); + }); + it('should handle space and send', function() { + const res = flow.parser.parse('graph TD;A-- text including URL space and send -->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow'); + expect(edges[0].text).toBe('text including URL space and send'); + }); + + it('should handle space and dir (TD)', function() { + const res = flow.parser.parse('graph TD;A--x|text including R TD space|B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + expect(edges[0].text).toBe('text including R TD space'); + }); + it('should handle `', function() { + const res = flow.parser.parse('graph TD;A--x|text including `|B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + expect(edges[0].text).toBe('text including `'); + }); + it('should handle v in node ids only v', function() { + // only v + const res = flow.parser.parse('graph TD;A--xv(my text);'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + expect(vert['v'].text).toBe('my text'); + }); + it('should handle v in node ids v at end', function() { + // v at end + const res = flow.parser.parse('graph TD;A--xcsv(my text);'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + expect(vert['csv'].text).toBe('my text'); + }); + it('should handle v in node ids v in middle', function() { + // v in middle + const res = flow.parser.parse('graph TD;A--xava(my text);'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + expect(vert['ava'].text).toBe('my text'); + }); + it('should handle v in node ids, v at start', function() { + // v at start + const res = flow.parser.parse('graph TD;A--xva(my text);'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + expect(vert['va'].text).toBe('my text'); + }); + it('should handle keywords', function() { + const res = flow.parser.parse('graph TD;A--x|text including graph space|B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].text).toBe('text including graph space'); + }); + it('should handle keywords', function() { + const res = flow.parser.parse('graph TD;V-->a[v]'); + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + expect(vert['a'].text).toBe('v'); + }); + it('should handle keywords', function() { + const res = flow.parser.parse('graph TD;V-->a[v]'); + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + expect(vert['a'].text).toBe('v'); + }); + it('should handle quoted text', function() { + const res = flow.parser.parse('graph TD;V-- "test string()" -->a[v]'); + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + expect(edges[0].text).toBe('test string()'); + }); + }); + + describe('it should handle new line type notation', function() { + it('it should handle regular lines', function() { + const res = flow.parser.parse('graph TD;A-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].stroke).toBe('normal'); + }); + it('it should handle dotted lines', function() { + const res = flow.parser.parse('graph TD;A-.->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].stroke).toBe('dotted'); + }); + it('it should handle dotted lines', function() { + const res = flow.parser.parse('graph TD;A==>B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].stroke).toBe('thick'); + }); + it('it should handle text on lines', function() { + const res = flow.parser.parse('graph TD;A-- test text with == -->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].stroke).toBe('normal'); + }); + it('it should handle text on lines', function() { + const res = flow.parser.parse('graph TD;A-. test text with == .->B;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].stroke).toBe('dotted') - }) - it('it should handle text on lines', function () { - const res = flow.parser.parse('graph TD;A== test text with - ==>B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].stroke).toBe('thick') - }) - }) - - describe('it should handle text on edges using the new notation', function () { - it('it should handle text without space', function () { - const res = flow.parser.parse('graph TD;A-- textNoSpace --xB;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - }) - - it('it should handle text with multiple leading space', function () { - const res = flow.parser.parse('graph TD;A-- textNoSpace --xB;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - }) - - it('should handle with space', function () { - const res = flow.parser.parse('graph TD;A-- text including space --xB;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - }) - - it('it should handle text with /', function () { - const res = flow.parser.parse('graph TD;A -- text with / should work --x B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].text).toBe('text with / should work') - }) - - it('it should handle space and space between vertices and link', function () { - const res = flow.parser.parse('graph TD;A -- textNoSpace --x B;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges[0].type).toBe('arrow_cross') - }) - - it('should handle space and CAPS', function () { - const res = flow.parser.parse('graph TD;A-- text including CAPS space --xB;') + expect(edges[0].stroke).toBe('dotted'); + }); + it('it should handle text on lines', function() { + const res = flow.parser.parse('graph TD;A== test text with - ==>B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].stroke).toBe('thick'); + }); + }); + + describe('it should handle text on edges using the new notation', function() { + it('it should handle text without space', function() { + const res = flow.parser.parse('graph TD;A-- textNoSpace --xB;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + }); + + it('it should handle text with multiple leading space', function() { + const res = flow.parser.parse('graph TD;A-- textNoSpace --xB;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + }); + + it('should handle with space', function() { + const res = flow.parser.parse('graph TD;A-- text including space --xB;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + }); + + it('it should handle text with /', function() { + const res = flow.parser.parse('graph TD;A -- text with / should work --x B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].text).toBe('text with / should work'); + }); + + it('it should handle space and space between vertices and link', function() { + const res = flow.parser.parse('graph TD;A -- textNoSpace --x B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges[0].type).toBe('arrow_cross'); + }); + + it('should handle space and CAPS', function() { + const res = flow.parser.parse('graph TD;A-- text including CAPS space --xB;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow_cross') - }) + expect(edges[0].type).toBe('arrow_cross'); + }); - it('should handle space and dir', function () { - const res = flow.parser.parse('graph TD;A-- text including URL space --xB;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + it('should handle space and dir', function() { + const res = flow.parser.parse('graph TD;A-- text including URL space --xB;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow_cross') - expect(edges[0].text).toBe('text including URL space') - }) - - it('should handle space and dir (TD)', function () { - const res = flow.parser.parse('graph TD;A-- text including R TD space --xB;') + expect(edges[0].type).toBe('arrow_cross'); + expect(edges[0].text).toBe('text including URL space'); + }); + + it('should handle space and dir (TD)', function() { + const res = flow.parser.parse('graph TD;A-- text including R TD space --xB;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow_cross') - expect(edges[0].text).toBe('text including R TD space') - }) - it('should handle keywords', function () { - const res = flow.parser.parse('graph TD;A-- text including graph space and v --xB;') + expect(edges[0].type).toBe('arrow_cross'); + expect(edges[0].text).toBe('text including R TD space'); + }); + it('should handle keywords', function() { + const res = flow.parser.parse('graph TD;A-- text including graph space and v --xB;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].text).toBe('text including graph space and v') - }) - it('should handle keywords', function () { - const res = flow.parser.parse('graph TD;A-- text including graph space and v --xB[blav]') + expect(edges[0].text).toBe('text including graph space and v'); + }); + it('should handle keywords', function() { + const res = flow.parser.parse('graph TD;A-- text including graph space and v --xB[blav]'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].text).toBe('text including graph space and v') - }) - // xit('should handle text on open links',function(){ - // const res = flow.parser.parse('graph TD;A-- text including graph space --B'); - // - // const vert = flow.parser.yy.getVertices(); - // const edges = flow.parser.yy.getEdges(); - // - // expect(edges[0].text).toBe('text including graph space'); - // - // }); - }) + expect(edges[0].text).toBe('text including graph space and v'); + }); + // xit('should handle text on open links',function(){ + // const res = flow.parser.parse('graph TD;A-- text including graph space --B'); + // + // const vert = flow.parser.yy.getVertices(); + // const edges = flow.parser.yy.getEdges(); + // + // expect(edges[0].text).toBe('text including graph space'); + // + // }); + }); - it('should handle multi-line text', function () { - const res = flow.parser.parse('graph TD;A--o|text space|B;\n B-->|more text with space|C;') + it('should handle multi-line text', function() { + const res = flow.parser.parse('graph TD;A--o|text space|B;\n B-->|more text with space|C;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow_circle') - expect(edges[1].type).toBe('arrow') - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(vert['C'].id).toBe('C') - expect(edges.length).toBe(2) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - // expect(edges[0].text).toBe('text space'); - expect(edges[1].start).toBe('B') - expect(edges[1].end).toBe('C') - expect(edges[1].text).toBe('more text with space') - }) + expect(edges[0].type).toBe('arrow_circle'); + expect(edges[1].type).toBe('arrow'); + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(vert['C'].id).toBe('C'); + expect(edges.length).toBe(2); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + // expect(edges[0].text).toBe('text space'); + expect(edges[1].start).toBe('B'); + expect(edges[1].end).toBe('C'); + expect(edges[1].text).toBe('more text with space'); + }); - it('should handle multiple edges', function () { - const res = flow.parser.parse('graph TD;A---|This is the 123 s text|B;\nA---|This is the second edge|B;') - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + it('should handle multiple edges', function() { + const res = flow.parser.parse( + 'graph TD;A---|This is the 123 s text|B;\nA---|This is the second edge|B;' + ); + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - expect(edges.length).toBe(2) - expect(edges[0].start).toBe('A') - expect(edges[0].end).toBe('B') - expect(edges[0].text).toBe('This is the 123 s text') - expect(edges[1].start).toBe('A') - expect(edges[1].end).toBe('B') - expect(edges[1].text).toBe('This is the second edge') - }) + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + expect(edges.length).toBe(2); + expect(edges[0].start).toBe('A'); + expect(edges[0].end).toBe('B'); + expect(edges[0].text).toBe('This is the 123 s text'); + expect(edges[1].start).toBe('A'); + expect(edges[1].end).toBe('B'); + expect(edges[1].text).toBe('This is the second edge'); + }); + + it('should handle text in vertices with space', function() { + const res = flow.parser.parse('graph TD;A[chimpansen hoppar]-->C;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].type).toBe('square'); + expect(vert['A'].text).toBe('chimpansen hoppar'); + }); + + it('should handle text in vertices with space with spaces between vertices and link', function() { + const res = flow.parser.parse('graph TD;A[chimpansen hoppar] --> C;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].type).toBe('square'); + expect(vert['A'].text).toBe('chimpansen hoppar'); + }); + it('should handle text including _ in vertices', function() { + const res = flow.parser.parse('graph TD;A[chimpansen_hoppar] --> C;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].type).toBe('square'); + expect(vert['A'].text).toBe('chimpansen_hoppar'); + }); + + it('should handle quoted text in vertices ', function() { + const res = flow.parser.parse('graph TD;A["chimpansen hoppar ()[]"] --> C;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].type).toBe('square'); + expect(vert['A'].text).toBe('chimpansen hoppar ()[]'); + }); + + it('should handle text in circle vertices with space', function() { + const res = flow.parser.parse('graph TD;A((chimpansen hoppar))-->C;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].type).toBe('circle'); + expect(vert['A'].text).toBe('chimpansen hoppar'); + }); + + it('should handle text in ellipse vertices', function() { + const res = flow.parser.parse('graph TD\nA(-this is an ellipse-)-->B'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].type).toBe('ellipse'); + expect(vert['A'].text).toBe('this is an ellipse'); + }); + + it('should handle text in diamond vertices with space', function() { + const res = flow.parser.parse('graph TD;A(chimpansen hoppar)-->C;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].type).toBe('round'); + expect(vert['A'].text).toBe('chimpansen hoppar'); + }); + + it('should handle text in with ?', function() { + const res = flow.parser.parse('graph TD;A(?)-->|?|C;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].text).toBe('?'); + expect(edges[0].text).toBe('?'); + }); + it('should handle text in with éèêàçô', function() { + const res = flow.parser.parse('graph TD;A(éèêàçô)-->|éèêàçô|C;'); - it('should handle text in vertices with space', function () { - const res = flow.parser.parse('graph TD;A[chimpansen hoppar]-->C;') + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].text).toBe('éèêàçô'); + expect(edges[0].text).toBe('éèêàçô'); + }); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + it('should handle text in with ,.?!+-*', function() { + const res = flow.parser.parse('graph TD;A(,.?!+-*)-->|,.?!+-*|C;'); - expect(vert['A'].type).toBe('square') - expect(vert['A'].text).toBe('chimpansen hoppar') - }) - - it('should handle text in vertices with space with spaces between vertices and link', function () { - const res = flow.parser.parse('graph TD;A[chimpansen hoppar] --> C;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].type).toBe('square') - expect(vert['A'].text).toBe('chimpansen hoppar') - }) - it('should handle text including _ in vertices', function () { - const res = flow.parser.parse('graph TD;A[chimpansen_hoppar] --> C;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].type).toBe('square') - expect(vert['A'].text).toBe('chimpansen_hoppar') - }) - - it('should handle quoted text in vertices ', function () { - const res = flow.parser.parse('graph TD;A["chimpansen hoppar ()[]"] --> C;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].type).toBe('square') - expect(vert['A'].text).toBe('chimpansen hoppar ()[]') - }) - - it('should handle text in circle vertices with space', function () { - const res = flow.parser.parse('graph TD;A((chimpansen hoppar))-->C;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].type).toBe('circle') - expect(vert['A'].text).toBe('chimpansen hoppar') - }) - - it('should handle text in ellipse vertices', function () { - const res = flow.parser.parse('graph TD\nA(-this is an ellipse-)-->B') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].type).toBe('ellipse') - expect(vert['A'].text).toBe('this is an ellipse') - }) - - it('should handle text in diamond vertices with space', function () { - const res = flow.parser.parse('graph TD;A(chimpansen hoppar)-->C;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].type).toBe('round') - expect(vert['A'].text).toBe('chimpansen hoppar') - }) - - it('should handle text in with ?', function () { - const res = flow.parser.parse('graph TD;A(?)-->|?|C;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['A'].text).toBe('?') - expect(edges[0].text).toBe('?') - }) - it('should handle text in with éèêàçô', function () { - const res = flow.parser.parse('graph TD;A(éèêàçô)-->|éèêàçô|C;') + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + expect(vert['A'].text).toBe(',.?!+-*'); + expect(edges[0].text).toBe(',.?!+-*'); + }); - expect(vert['A'].text).toBe('éèêàçô') - expect(edges[0].text).toBe('éèêàçô') - }) + describe('it should handle text in vertices, ', function() { + it('it should handle space', function() { + const res = flow.parser.parse('graph TD;A-->C(Chimpansen hoppar);'); - it('should handle text in with ,.?!+-*', function () { - const res = flow.parser.parse('graph TD;A(,.?!+-*)-->|,.?!+-*|C;') + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + expect(vert['C'].type).toBe('round'); + expect(vert['C'].text).toBe('Chimpansen hoppar'); + }); + it('it should handle åäö and minus', function() { + const res = flow.parser.parse('graph TD;A-->C{Chimpansen hoppar åäö-ÅÄÖ};'); - expect(vert['A'].text).toBe(',.?!+-*') - expect(edges[0].text).toBe(',.?!+-*') - }) + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - describe('it should handle text in vertices, ', function () { - it('it should handle space', function () { - const res = flow.parser.parse('graph TD;A-->C(Chimpansen hoppar);') + expect(vert['C'].type).toBe('diamond'); + expect(vert['C'].text).toBe('Chimpansen hoppar åäö-ÅÄÖ'); + }); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + it('it should handle with åäö, minus and space and br', function() { + const res = flow.parser.parse('graph TD;A-->C(Chimpansen hoppar åäö
- ÅÄÖ);'); - expect(vert['C'].type).toBe('round') - expect(vert['C'].text).toBe('Chimpansen hoppar') - }) - it('it should handle åäö and minus', function () { - const res = flow.parser.parse('graph TD;A-->C{Chimpansen hoppar åäö-ÅÄÖ};') + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['C'].type).toBe('diamond') - expect(vert['C'].text).toBe('Chimpansen hoppar åäö-ÅÄÖ') - }) - - it('it should handle with åäö, minus and space and br', function () { - const res = flow.parser.parse('graph TD;A-->C(Chimpansen hoppar åäö
- ÅÄÖ);') + expect(vert['C'].type).toBe('round'); + expect(vert['C'].text).toBe('Chimpansen hoppar åäö
- ÅÄÖ'); + }); + // xit('it should handle åäö, minus and space and br',function(){ + // const res = flow.parser.parse('graph TD; A[Object(foo,bar)]-->B(Thing);'); + // + // const vert = flow.parser.yy.getVertices(); + // const edges = flow.parser.yy.getEdges(); + // + // expect(vert['C'].type).toBe('round'); + // expect(vert['C'].text).toBe(' A[Object(foo,bar)]-->B(Thing);'); + // }); + it('it should handle unicode chars', function() { + const res = flow.parser.parse('graph TD;A-->C(Начало);'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['C'].type).toBe('round') - expect(vert['C'].text).toBe('Chimpansen hoppar åäö
- ÅÄÖ') - }) - // xit('it should handle åäö, minus and space and br',function(){ - // const res = flow.parser.parse('graph TD; A[Object(foo,bar)]-->B(Thing);'); - // - // const vert = flow.parser.yy.getVertices(); - // const edges = flow.parser.yy.getEdges(); - // - // expect(vert['C'].type).toBe('round'); - // expect(vert['C'].text).toBe(' A[Object(foo,bar)]-->B(Thing);'); - // }); - it('it should handle unicode chars', function () { - const res = flow.parser.parse('graph TD;A-->C(Начало);') - - const vert = flow.parser.yy.getVertices() - - expect(vert['C'].text).toBe('Начало') - }) - it('it should handle backslask', function () { - const res = flow.parser.parse('graph TD;A-->C(c:\\windows);') - - const vert = flow.parser.yy.getVertices() - - expect(vert['C'].text).toBe('c:\\windows') - }) - it('it should handle CAPS', function () { - const res = flow.parser.parse('graph TD;A-->C(some CAPS);') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['C'].type).toBe('round') - expect(vert['C'].text).toBe('some CAPS') - }) - it('it should handle directions', function () { - const res = flow.parser.parse('graph TD;A-->C(some URL);') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(vert['C'].type).toBe('round') - expect(vert['C'].text).toBe('some URL') - }) - }) - - it('should handle a single node', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;A;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['A'].styles.length).toBe(0) - }) - - it('should handle a single square node', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;a[A];') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['a'].styles.length).toBe(0) - expect(vert['a'].type).toBe('square') - }) - it('should handle a single round square node', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;a[A];') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['a'].styles.length).toBe(0) - expect(vert['a'].type).toBe('square') - }) - it('should handle a single circle node', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;a((A));') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['a'].type).toBe('circle') - }) - it('should handle a single round node', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;a(A);') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['a'].type).toBe('round') - }) - it('should handle a single odd node', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;a>A];') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['a'].type).toBe('odd') - }) - it('should handle a single diamond node', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;a{A};') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['a'].type).toBe('diamond') - }) - it('should handle a single diamond node with html in it', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;a{A
end};') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['a'].type).toBe('diamond') - expect(vert['a'].text).toBe('A
end') - }) - it('should handle a single round node with html in it', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;a(A
end);') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['a'].type).toBe('round') - expect(vert['a'].text).toBe('A
end') - }) - it('should handle a single node with alphanumerics starting on a char', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;id1;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['id1'].styles.length).toBe(0) - }) - it('should handle a single node with a single digit', function () { + const vert = flow.parser.yy.getVertices(); + + expect(vert['C'].text).toBe('Начало'); + }); + it('it should handle backslask', function() { + const res = flow.parser.parse('graph TD;A-->C(c:\\windows);'); + + const vert = flow.parser.yy.getVertices(); + + expect(vert['C'].text).toBe('c:\\windows'); + }); + it('it should handle CAPS', function() { + const res = flow.parser.parse('graph TD;A-->C(some CAPS);'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['C'].type).toBe('round'); + expect(vert['C'].text).toBe('some CAPS'); + }); + it('it should handle directions', function() { + const res = flow.parser.parse('graph TD;A-->C(some URL);'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['C'].type).toBe('round'); + expect(vert['C'].text).toBe('some URL'); + }); + }); + + it('should handle a single node', function() { // Silly but syntactically correct - const res = flow.parser.parse('graph TD;1;') + const res = flow.parser.parse('graph TD;A;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges.length).toBe(0) - expect(vert['s1'].text).toBe('1') - }) - it('should handle a single node with a single digit in a subgraph', function () { + expect(edges.length).toBe(0); + expect(vert['A'].styles.length).toBe(0); + }); + + it('should handle a single square node', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;a[A];'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['a'].styles.length).toBe(0); + expect(vert['a'].type).toBe('square'); + }); + it('should handle a single round square node', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;a[A];'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['a'].styles.length).toBe(0); + expect(vert['a'].type).toBe('square'); + }); + it('should handle a single circle node', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;a((A));'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['a'].type).toBe('circle'); + }); + it('should handle a single round node', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;a(A);'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['a'].type).toBe('round'); + }); + it('should handle a single odd node', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;a>A];'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['a'].type).toBe('odd'); + }); + it('should handle a single diamond node', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;a{A};'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['a'].type).toBe('diamond'); + }); + it('should handle a single diamond node with html in it', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;a{A
end};'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['a'].type).toBe('diamond'); + expect(vert['a'].text).toBe('A
end'); + }); + it('should handle a single round node with html in it', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;a(A
end);'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['a'].type).toBe('round'); + expect(vert['a'].text).toBe('A
end'); + }); + it('should handle a single node with alphanumerics starting on a char', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;id1;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['id1'].styles.length).toBe(0); + }); + it('should handle a single node with a single digit', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;1;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(edges.length).toBe(0); + expect(vert['s1'].text).toBe('1'); + }); + it('should handle a single node with a single digit in a subgraph', function() { // Silly but syntactically correct - const res = flow.parser.parse('graph TD;subgraph "hello";1;end;') + const res = flow.parser.parse('graph TD;subgraph "hello";1;end;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges.length).toBe(0) - expect(vert['s1'].text).toBe('1') - }) - it('should handle a single node with alphanumerics starting on a num', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;1id;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['s1id'].styles.length).toBe(0) - }) - it('should handle a single node with alphanumerics containing a minus sign', function () { - // Silly but syntactically correct - const res = flow.parser.parse('graph TD;i-d;') - - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() - - expect(edges.length).toBe(0) - expect(vert['i-d'].styles.length).toBe(0) - }) - it('should handle a single node with alphanumerics containing a underscore sign', function () { + expect(edges.length).toBe(0); + expect(vert['s1'].text).toBe('1'); + }); + it('should handle a single node with alphanumerics starting on a num', function() { // Silly but syntactically correct - const res = flow.parser.parse('graph TD;i_d;') + const res = flow.parser.parse('graph TD;1id;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges.length).toBe(0) - expect(vert['i_d'].styles.length).toBe(0) - }) + expect(edges.length).toBe(0); + expect(vert['s1id'].styles.length).toBe(0); + }); + it('should handle a single node with alphanumerics containing a minus sign', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;i-d;'); - // log.debug(flow.parser.parse('graph TD;style Q background:#fff;')); - it('should handle styles for vertices', function () { - const res = flow.parser.parse('graph TD;style Q background:#fff;') + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + expect(edges.length).toBe(0); + expect(vert['i-d'].styles.length).toBe(0); + }); + it('should handle a single node with alphanumerics containing a underscore sign', function() { + // Silly but syntactically correct + const res = flow.parser.parse('graph TD;i_d;'); - const style = vert['Q'].styles[0] + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(vert['Q'].styles.length).toBe(1) - expect(vert['Q'].styles[0]).toBe('background:#fff') - }) + expect(edges.length).toBe(0); + expect(vert['i_d'].styles.length).toBe(0); + }); - // log.debug(flow.parser.parse('graph TD;style Q background:#fff;')); - it('should handle styles for edges', function () { - const res = flow.parser.parse('graph TD;a-->b;\nstyle #0 stroke: #f66;') + // log.debug(flow.parser.parse('graph TD;style Q background:#fff;')); + it('should handle styles for vertices', function() { + const res = flow.parser.parse('graph TD;style Q background:#fff;'); - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges.length).toBe(1) - }) + const style = vert['Q'].styles[0]; - it('should handle multiple styles for a vortex', function () { - const res = flow.parser.parse('graph TD;style R background:#fff,border:1px solid red;') + expect(vert['Q'].styles.length).toBe(1); + expect(vert['Q'].styles[0]).toBe('background:#fff'); + }); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + // log.debug(flow.parser.parse('graph TD;style Q background:#fff;')); + it('should handle styles for edges', function() { + const res = flow.parser.parse('graph TD;a-->b;\nstyle #0 stroke: #f66;'); - expect(vert['R'].styles.length).toBe(2) - expect(vert['R'].styles[0]).toBe('background:#fff') - expect(vert['R'].styles[1]).toBe('border:1px solid red') - }) + const edges = flow.parser.yy.getEdges(); - it('should handle multiple styles in a graph', function () { - const res = flow.parser.parse('graph TD;style S background:#aaa;\nstyle T background:#bbb,border:1px solid red;') + expect(edges.length).toBe(1); + }); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + it('should handle multiple styles for a vortex', function() { + const res = flow.parser.parse('graph TD;style R background:#fff,border:1px solid red;'); - expect(vert['S'].styles.length).toBe(1) - expect(vert['T'].styles.length).toBe(2) - expect(vert['S'].styles[0]).toBe('background:#aaa') - expect(vert['T'].styles[0]).toBe('background:#bbb') - expect(vert['T'].styles[1]).toBe('border:1px solid red') - }) + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - it('should handle styles and graph definitons in a graph', function () { - const res = flow.parser.parse('graph TD;S-->T;\nstyle S background:#aaa;\nstyle T background:#bbb,border:1px solid red;') + expect(vert['R'].styles.length).toBe(2); + expect(vert['R'].styles[0]).toBe('background:#fff'); + expect(vert['R'].styles[1]).toBe('border:1px solid red'); + }); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + it('should handle multiple styles in a graph', function() { + const res = flow.parser.parse( + 'graph TD;style S background:#aaa;\nstyle T background:#bbb,border:1px solid red;' + ); - expect(vert['S'].styles.length).toBe(1) - expect(vert['T'].styles.length).toBe(2) - expect(vert['S'].styles[0]).toBe('background:#aaa') - expect(vert['T'].styles[0]).toBe('background:#bbb') - expect(vert['T'].styles[1]).toBe('border:1px solid red') - }) - it('should handle styles and graph definitons in a graph', function () { - const res = flow.parser.parse('graph TD;style T background:#bbb,border:1px solid red;') - // const res = flow.parser.parse('graph TD;style T background: #bbb;'); + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const vert = flow.parser.yy.getVertices() + expect(vert['S'].styles.length).toBe(1); + expect(vert['T'].styles.length).toBe(2); + expect(vert['S'].styles[0]).toBe('background:#aaa'); + expect(vert['T'].styles[0]).toBe('background:#bbb'); + expect(vert['T'].styles[1]).toBe('border:1px solid red'); + }); - expect(vert['T'].styles.length).toBe(2) - expect(vert['T'].styles[0]).toBe('background:#bbb') - expect(vert['T'].styles[1]).toBe('border:1px solid red') - }) + it('should handle styles and graph definitons in a graph', function() { + const res = flow.parser.parse( + 'graph TD;S-->T;\nstyle S background:#aaa;\nstyle T background:#bbb,border:1px solid red;' + ); - describe('special characters should be be handled.', function () { - const charTest = function (char, result) { - const res = flow.parser.parse('graph TD;A(' + char + ')-->B;') + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + expect(vert['S'].styles.length).toBe(1); + expect(vert['T'].styles.length).toBe(2); + expect(vert['S'].styles[0]).toBe('background:#aaa'); + expect(vert['T'].styles[0]).toBe('background:#bbb'); + expect(vert['T'].styles[1]).toBe('border:1px solid red'); + }); + it('should handle styles and graph definitons in a graph', function() { + const res = flow.parser.parse('graph TD;style T background:#bbb,border:1px solid red;'); + // const res = flow.parser.parse('graph TD;style T background: #bbb;'); - expect(vert['A'].id).toBe('A') - expect(vert['B'].id).toBe('B') - if(result){ - expect(vert['A'].text).toBe(result) - }else{ - expect(vert['A'].text).toBe(char) + const vert = flow.parser.yy.getVertices(); + + expect(vert['T'].styles.length).toBe(2); + expect(vert['T'].styles[0]).toBe('background:#bbb'); + expect(vert['T'].styles[1]).toBe('border:1px solid red'); + }); + + describe('special characters should be be handled.', function() { + const charTest = function(char, result) { + const res = flow.parser.parse('graph TD;A(' + char + ')-->B;'); + + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); + + expect(vert['A'].id).toBe('A'); + expect(vert['B'].id).toBe('B'); + if (result) { + expect(vert['A'].text).toBe(result); + } else { + expect(vert['A'].text).toBe(char); } - } + }; - it('it should be able to parse a \'.\'', function () { - charTest('.') - charTest('Start 103a.a1') - }) + it("it should be able to parse a '.'", function() { + charTest('.'); + charTest('Start 103a.a1'); + }); // it('it should be able to parse text containing \'_\'', function () { // charTest('_') // }) - it('it should be able to parse a \':\'', function () { - charTest(':') - }) + it("it should be able to parse a ':'", function() { + charTest(':'); + }); - it('it should be able to parse a \',\'', function () { - charTest(',') - }) + it("it should be able to parse a ','", function() { + charTest(','); + }); - it('it should be able to parse text containing \'-\'', function () { - charTest('a-b') - }) + it("it should be able to parse text containing '-'", function() { + charTest('a-b'); + }); - it('it should be able to parse a \'+\'', function () { - charTest('+') - }) + it("it should be able to parse a '+'", function() { + charTest('+'); + }); - it('it should be able to parse a \'*\'', function () { - charTest('*') - }) + it("it should be able to parse a '*'", function() { + charTest('*'); + }); - it('it should be able to parse a \'<\'', function () { - charTest('<','<') - }) + it("it should be able to parse a '<'", function() { + charTest('<', '<'); + }); - it('it should be able to parse a \'>\'', function () { - charTest('>','>') - }) + it("it should be able to parse a '>'", function() { + charTest('>', '>'); + }); - it('it should be able to parse a \'=\'', function () { - charTest('=','=') - }) - it('it should be able to parse a \'&\'', function () { - charTest('&') - }) - }) + it("it should be able to parse a '='", function() { + charTest('=', '='); + }); + it("it should be able to parse a '&'", function() { + charTest('&'); + }); + }); - it('should be possible to declare a class', function () { - const res = flow.parser.parse('graph TD;classDef exClass background:#bbb,border:1px solid red;') - // const res = flow.parser.parse('graph TD;style T background: #bbb;'); + it('should be possible to declare a class', function() { + const res = flow.parser.parse( + 'graph TD;classDef exClass background:#bbb,border:1px solid red;' + ); + // const res = flow.parser.parse('graph TD;style T background: #bbb;'); - const classes = flow.parser.yy.getClasses() + const classes = flow.parser.yy.getClasses(); - expect(classes['exClass'].styles.length).toBe(2) - expect(classes['exClass'].styles[0]).toBe('background:#bbb') - expect(classes['exClass'].styles[1]).toBe('border:1px solid red') - }) + expect(classes['exClass'].styles.length).toBe(2); + expect(classes['exClass'].styles[0]).toBe('background:#bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1px solid red'); + }); - it('should be possible to declare a class with a dot in the style', function () { - const res = flow.parser.parse('graph TD;classDef exClass background:#bbb,border:1.5px solid red;') - // const res = flow.parser.parse('graph TD;style T background: #bbb;'); + it('should be possible to declare a class with a dot in the style', function() { + const res = flow.parser.parse( + 'graph TD;classDef exClass background:#bbb,border:1.5px solid red;' + ); + // const res = flow.parser.parse('graph TD;style T background: #bbb;'); - const classes = flow.parser.yy.getClasses() + const classes = flow.parser.yy.getClasses(); - expect(classes['exClass'].styles.length).toBe(2) - expect(classes['exClass'].styles[0]).toBe('background:#bbb') - expect(classes['exClass'].styles[1]).toBe('border:1.5px solid red') - }) - it('should be possible to declare a class with a space in the style', function () { - const res = flow.parser.parse('graph TD;classDef exClass background: #bbb,border:1.5px solid red;') - // const res = flow.parser.parse('graph TD;style T background : #bbb;'); + expect(classes['exClass'].styles.length).toBe(2); + expect(classes['exClass'].styles[0]).toBe('background:#bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1.5px solid red'); + }); + it('should be possible to declare a class with a space in the style', function() { + const res = flow.parser.parse( + 'graph TD;classDef exClass background: #bbb,border:1.5px solid red;' + ); + // const res = flow.parser.parse('graph TD;style T background : #bbb;'); - const classes = flow.parser.yy.getClasses() + const classes = flow.parser.yy.getClasses(); - expect(classes['exClass'].styles.length).toBe(2) - expect(classes['exClass'].styles[0]).toBe('background: #bbb') - expect(classes['exClass'].styles[1]).toBe('border:1.5px solid red') - }) - it('should be possible to apply a class to a vertex', function () { - let statement = '' + expect(classes['exClass'].styles.length).toBe(2); + expect(classes['exClass'].styles[0]).toBe('background: #bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1.5px solid red'); + }); + it('should be possible to apply a class to a vertex', function() { + let statement = ''; - statement = statement + 'graph TD;' + '\n' - statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n' - statement = statement + 'a-->b;' + '\n' - statement = statement + 'class a exClass;' + statement = statement + 'graph TD;' + '\n'; + statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n'; + statement = statement + 'a-->b;' + '\n'; + statement = statement + 'class a exClass;'; - const res = flow.parser.parse(statement) + const res = flow.parser.parse(statement); - const classes = flow.parser.yy.getClasses() + const classes = flow.parser.yy.getClasses(); - expect(classes['exClass'].styles.length).toBe(2) - expect(classes['exClass'].styles[0]).toBe('background:#bbb') - expect(classes['exClass'].styles[1]).toBe('border:1px solid red') - }) - it('should be possible to apply a class to a vertex with an id containing _', function () { - let statement = '' + expect(classes['exClass'].styles.length).toBe(2); + expect(classes['exClass'].styles[0]).toBe('background:#bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1px solid red'); + }); + it('should be possible to apply a class to a vertex with an id containing _', function() { + let statement = ''; - statement = statement + 'graph TD;' + '\n' - statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n' - statement = statement + 'a_a-->b_b;' + '\n' - statement = statement + 'class a_a exClass;' + statement = statement + 'graph TD;' + '\n'; + statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n'; + statement = statement + 'a_a-->b_b;' + '\n'; + statement = statement + 'class a_a exClass;'; - const res = flow.parser.parse(statement) + const res = flow.parser.parse(statement); - const classes = flow.parser.yy.getClasses() + const classes = flow.parser.yy.getClasses(); - expect(classes['exClass'].styles.length).toBe(2) - expect(classes['exClass'].styles[0]).toBe('background:#bbb') - expect(classes['exClass'].styles[1]).toBe('border:1px solid red') - }) - it('should be possible to apply a class to a vertex directly', function () { - let statement = '' + expect(classes['exClass'].styles.length).toBe(2); + expect(classes['exClass'].styles[0]).toBe('background:#bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1px solid red'); + }); + it('should be possible to apply a class to a vertex directly', function() { + let statement = ''; - statement = statement + 'graph TD;' + '\n' - statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n' - statement = statement + 'a-->b[test]:::exClass;' + '\n' + statement = statement + 'graph TD;' + '\n'; + statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n'; + statement = statement + 'a-->b[test]:::exClass;' + '\n'; - const res = flow.parser.parse(statement) - const vertices = flow.parser.yy.getVertices() - const classes = flow.parser.yy.getClasses() + const res = flow.parser.parse(statement); + const vertices = flow.parser.yy.getVertices(); + const classes = flow.parser.yy.getClasses(); - expect(classes['exClass'].styles.length).toBe(2) - expect(vertices['b'].classes[0]).toBe('exClass') - expect(classes['exClass'].styles[0]).toBe('background:#bbb') - expect(classes['exClass'].styles[1]).toBe('border:1px solid red') - }) + expect(classes['exClass'].styles.length).toBe(2); + expect(vertices['b'].classes[0]).toBe('exClass'); + expect(classes['exClass'].styles[0]).toBe('background:#bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1px solid red'); + }); - it('should be possible to apply a class to a vertex directly : usecase A[text].class ', function () { - let statement = '' + it('should be possible to apply a class to a vertex directly : usecase A[text].class ', function() { + let statement = ''; - statement = statement + 'graph TD;' + '\n' - statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n' - statement = statement + 'b[test]:::exClass;' + '\n' + statement = statement + 'graph TD;' + '\n'; + statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n'; + statement = statement + 'b[test]:::exClass;' + '\n'; - const res = flow.parser.parse(statement) - const vertices = flow.parser.yy.getVertices() - const classes = flow.parser.yy.getClasses() + const res = flow.parser.parse(statement); + const vertices = flow.parser.yy.getVertices(); + const classes = flow.parser.yy.getClasses(); - expect(classes['exClass'].styles.length).toBe(2) - expect(vertices['b'].classes[0]).toBe('exClass') - expect(classes['exClass'].styles[0]).toBe('background:#bbb') - expect(classes['exClass'].styles[1]).toBe('border:1px solid red') - }) + expect(classes['exClass'].styles.length).toBe(2); + expect(vertices['b'].classes[0]).toBe('exClass'); + expect(classes['exClass'].styles[0]).toBe('background:#bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1px solid red'); + }); - it('should be possible to apply a class to a vertex directly : usecase A[text].class-->B[test2] ', function () { - let statement = '' + it('should be possible to apply a class to a vertex directly : usecase A[text].class-->B[test2] ', function() { + let statement = ''; - statement = statement + 'graph TD;' + '\n' - statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n' - statement = statement + 'A[test]:::exClass-->B[test2];' + '\n' + statement = statement + 'graph TD;' + '\n'; + statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n'; + statement = statement + 'A[test]:::exClass-->B[test2];' + '\n'; - const res = flow.parser.parse(statement) - const vertices = flow.parser.yy.getVertices() - const classes = flow.parser.yy.getClasses() + const res = flow.parser.parse(statement); + const vertices = flow.parser.yy.getVertices(); + const classes = flow.parser.yy.getClasses(); - expect(classes['exClass'].styles.length).toBe(2) - expect(vertices['A'].classes[0]).toBe('exClass') - expect(classes['exClass'].styles[0]).toBe('background:#bbb') - expect(classes['exClass'].styles[1]).toBe('border:1px solid red') - }) + expect(classes['exClass'].styles.length).toBe(2); + expect(vertices['A'].classes[0]).toBe('exClass'); + expect(classes['exClass'].styles[0]).toBe('background:#bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1px solid red'); + }); - it('should be possible to apply a class to a vertex directly 2', function () { - let statement = '' + it('should be possible to apply a class to a vertex directly 2', function() { + let statement = ''; - statement = statement + 'graph TD;' + '\n' - statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n' - statement = statement + 'a-->b[1 a a text!.]:::exClass;' + '\n' + statement = statement + 'graph TD;' + '\n'; + statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n'; + statement = statement + 'a-->b[1 a a text!.]:::exClass;' + '\n'; - const res = flow.parser.parse(statement) - const vertices = flow.parser.yy.getVertices() - const classes = flow.parser.yy.getClasses() + const res = flow.parser.parse(statement); + const vertices = flow.parser.yy.getVertices(); + const classes = flow.parser.yy.getClasses(); - expect(classes['exClass'].styles.length).toBe(2) - expect(vertices['b'].classes[0]).toBe('exClass') - expect(classes['exClass'].styles[0]).toBe('background:#bbb') - expect(classes['exClass'].styles[1]).toBe('border:1px solid red') - }) - it('should be possible to apply a class to a comma separated list of vertices', function () { - let statement = '' + expect(classes['exClass'].styles.length).toBe(2); + expect(vertices['b'].classes[0]).toBe('exClass'); + expect(classes['exClass'].styles[0]).toBe('background:#bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1px solid red'); + }); + it('should be possible to apply a class to a comma separated list of vertices', function() { + let statement = ''; - statement = statement + 'graph TD;' + '\n' - statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n' - statement = statement + 'a-->b;' + '\n' - statement = statement + 'class a,b exClass;' + statement = statement + 'graph TD;' + '\n'; + statement = statement + 'classDef exClass background:#bbb,border:1px solid red;' + '\n'; + statement = statement + 'a-->b;' + '\n'; + statement = statement + 'class a,b exClass;'; - const res = flow.parser.parse(statement) + const res = flow.parser.parse(statement); - const classes = flow.parser.yy.getClasses() - const vertices = flow.parser.yy.getVertices() + const classes = flow.parser.yy.getClasses(); + const vertices = flow.parser.yy.getVertices(); - expect(classes['exClass'].styles.length).toBe(2) - expect(classes['exClass'].styles[0]).toBe('background:#bbb') - expect(classes['exClass'].styles[1]).toBe('border:1px solid red') - expect(vertices['a'].classes[0]).toBe('exClass') - expect(vertices['b'].classes[0]).toBe('exClass') - }) -}) + expect(classes['exClass'].styles.length).toBe(2); + expect(classes['exClass'].styles[0]).toBe('background:#bbb'); + expect(classes['exClass'].styles[1]).toBe('border:1px solid red'); + expect(vertices['a'].classes[0]).toBe('exClass'); + expect(vertices['b'].classes[0]).toBe('exClass'); + }); +}); diff --git a/src/diagrams/flowchart/parser/subgraph.spec.js b/src/diagrams/flowchart/parser/subgraph.spec.js index 6a33c30be..0bf3e63d6 100644 --- a/src/diagrams/flowchart/parser/subgraph.spec.js +++ b/src/diagrams/flowchart/parser/subgraph.spec.js @@ -1,223 +1,223 @@ -import flowDb from '../flowDb' -import flow from './flow' -import { setConfig } from '../../../config' +import flowDb from '../flowDb'; +import flow from './flow'; +import { setConfig } from '../../../config'; setConfig({ - securityLevel: 'strict', -}) + securityLevel: 'strict' +}); -describe('when parsing subgraphs', function () { - beforeEach(function () { - flow.parser.yy = flowDb - flow.parser.yy.clear() - }) - it('should handle subgraph with tab indentation', function () { - const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2\nend') - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] - expect(subgraph.nodes.length).toBe(2) - expect(subgraph.nodes[0]).toBe('a2') - expect(subgraph.nodes[1]).toBe('a1') - expect(subgraph.title).toBe('One') - expect(subgraph.id).toBe('One') - }) - it('should handle subgraph with chaining nodes indentation', function () { - const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2-->a3\nend') - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] - expect(subgraph.nodes.length).toBe(3) - expect(subgraph.nodes[0]).toBe('a3') - expect(subgraph.nodes[1]).toBe('a2') - expect(subgraph.nodes[2]).toBe('a1') - expect(subgraph.title).toBe('One') - expect(subgraph.id).toBe('One') - }) - - it('should handle subgraph with multiple words in title', function () { - const res = flow.parser.parse('graph TB\nsubgraph "Some Title"\n\ta1-->a2\nend') - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] - expect(subgraph.nodes.length).toBe(2) - expect(subgraph.nodes[0]).toBe('a2') - expect(subgraph.nodes[1]).toBe('a1') - expect(subgraph.title).toBe('Some Title') - expect(subgraph.id).toBe('subGraph0') +describe('when parsing subgraphs', function() { + beforeEach(function() { + flow.parser.yy = flowDb; + flow.parser.yy.clear(); + }); + it('should handle subgraph with tab indentation', function() { + const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2\nend'); + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; + expect(subgraph.nodes.length).toBe(2); + expect(subgraph.nodes[0]).toBe('a2'); + expect(subgraph.nodes[1]).toBe('a1'); + expect(subgraph.title).toBe('One'); + expect(subgraph.id).toBe('One'); + }); + it('should handle subgraph with chaining nodes indentation', function() { + const res = flow.parser.parse('graph TB\nsubgraph One\n\ta1-->a2-->a3\nend'); + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; + expect(subgraph.nodes.length).toBe(3); + expect(subgraph.nodes[0]).toBe('a3'); + expect(subgraph.nodes[1]).toBe('a2'); + expect(subgraph.nodes[2]).toBe('a1'); + expect(subgraph.title).toBe('One'); + expect(subgraph.id).toBe('One'); }); - it('should handle subgraph with id and title notation', function () { - const res = flow.parser.parse('graph TB\nsubgraph some-id[Some Title]\n\ta1-->a2\nend') - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] - expect(subgraph.nodes.length).toBe(2) - expect(subgraph.nodes[0]).toBe('a2') - expect(subgraph.nodes[1]).toBe('a1') - expect(subgraph.title).toBe('Some Title') - expect(subgraph.id).toBe('some-id') + it('should handle subgraph with multiple words in title', function() { + const res = flow.parser.parse('graph TB\nsubgraph "Some Title"\n\ta1-->a2\nend'); + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; + expect(subgraph.nodes.length).toBe(2); + expect(subgraph.nodes[0]).toBe('a2'); + expect(subgraph.nodes[1]).toBe('a1'); + expect(subgraph.title).toBe('Some Title'); + expect(subgraph.id).toBe('subGraph0'); }); - xit('should handle subgraph without id and space in title', function () { - const res = flow.parser.parse('graph TB\nsubgraph Some Title\n\ta1-->a2\nend') - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] - expect(subgraph.nodes.length).toBe(2) - expect(subgraph.nodes[0]).toBe('a1') - expect(subgraph.nodes[1]).toBe('a2') - expect(subgraph.title).toBe('Some Title') - expect(subgraph.id).toBe('some-id') + it('should handle subgraph with id and title notation', function() { + const res = flow.parser.parse('graph TB\nsubgraph some-id[Some Title]\n\ta1-->a2\nend'); + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; + expect(subgraph.nodes.length).toBe(2); + expect(subgraph.nodes[0]).toBe('a2'); + expect(subgraph.nodes[1]).toBe('a1'); + expect(subgraph.title).toBe('Some Title'); + expect(subgraph.id).toBe('some-id'); }); - it('should handle subgraph id starting with a number', function () { + xit('should handle subgraph without id and space in title', function() { + const res = flow.parser.parse('graph TB\nsubgraph Some Title\n\ta1-->a2\nend'); + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; + expect(subgraph.nodes.length).toBe(2); + expect(subgraph.nodes[0]).toBe('a1'); + expect(subgraph.nodes[1]).toBe('a2'); + expect(subgraph.title).toBe('Some Title'); + expect(subgraph.id).toBe('some-id'); + }); + + it('should handle subgraph id starting with a number', function() { const res = flow.parser.parse(`graph TD A[Christmas] -->|Get money| B(Go shopping) subgraph 1test A - end`) + end`); - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] - expect(subgraph.nodes.length).toBe(1) - expect(subgraph.nodes[0]).toBe('A') - expect(subgraph.id).toBe('s1test') + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; + expect(subgraph.nodes.length).toBe(1); + expect(subgraph.nodes[0]).toBe('A'); + expect(subgraph.id).toBe('s1test'); }); - it('should handle subgraphs1', function () { - const res = flow.parser.parse('graph TD;A-->B;subgraph myTitle;c-->d;end;') + it('should handle subgraphs1', function() { + const res = flow.parser.parse('graph TD;A-->B;subgraph myTitle;c-->d;end;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow') - }) - it('should handle subgraphs with title in quotes', function () { - const res = flow.parser.parse('graph TD;A-->B;subgraph "title in quotes";c-->d;end;') + expect(edges[0].type).toBe('arrow'); + }); + it('should handle subgraphs with title in quotes', function() { + const res = flow.parser.parse('graph TD;A-->B;subgraph "title in quotes";c-->d;end;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; - expect(subgraph.title).toBe('title in quotes') + expect(subgraph.title).toBe('title in quotes'); - expect(edges[0].type).toBe('arrow') - }) - it('should handle subgraphs in old style that was broken', function () { - const res = flow.parser.parse('graph TD;A-->B;subgraph old style that is broken;c-->d;end;') + expect(edges[0].type).toBe('arrow'); + }); + it('should handle subgraphs in old style that was broken', function() { + const res = flow.parser.parse('graph TD;A-->B;subgraph old style that is broken;c-->d;end;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; - expect(subgraph.title).toBe('old style that is broken') + expect(subgraph.title).toBe('old style that is broken'); - expect(edges[0].type).toBe('arrow') - }) - it('should handle subgraphs with dashes in the title', function () { - const res = flow.parser.parse('graph TD;A-->B;subgraph a-b-c;c-->d;end;') + expect(edges[0].type).toBe('arrow'); + }); + it('should handle subgraphs with dashes in the title', function() { + const res = flow.parser.parse('graph TD;A-->B;subgraph a-b-c;c-->d;end;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; - expect(subgraph.title).toBe('a-b-c') + expect(subgraph.title).toBe('a-b-c'); - expect(edges[0].type).toBe('arrow') - }) - it('should handle subgraphs with id and title in brackets', function () { - const res = flow.parser.parse('graph TD;A-->B;subgraph uid1[text of doom];c-->d;end;') + expect(edges[0].type).toBe('arrow'); + }); + it('should handle subgraphs with id and title in brackets', function() { + const res = flow.parser.parse('graph TD;A-->B;subgraph uid1[text of doom];c-->d;end;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; - expect(subgraph.title).toBe('text of doom') - expect(subgraph.id).toBe('uid1') + expect(subgraph.title).toBe('text of doom'); + expect(subgraph.id).toBe('uid1'); - expect(edges[0].type).toBe('arrow') - }) - it('should handle subgraphs with id and title in brackets and quotes', function () { - const res = flow.parser.parse('graph TD;A-->B;subgraph uid2["text of doom"];c-->d;end;') + expect(edges[0].type).toBe('arrow'); + }); + it('should handle subgraphs with id and title in brackets and quotes', function() { + const res = flow.parser.parse('graph TD;A-->B;subgraph uid2["text of doom"];c-->d;end;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; - expect(subgraph.title).toBe('text of doom') - expect(subgraph.id).toBe('uid2') + expect(subgraph.title).toBe('text of doom'); + expect(subgraph.id).toBe('uid2'); - expect(edges[0].type).toBe('arrow') - }) - it('should handle subgraphs with id and title in brackets without spaces', function () { - const res = flow.parser.parse('graph TD;A-->B;subgraph uid2[textofdoom];c-->d;end;') + expect(edges[0].type).toBe('arrow'); + }); + it('should handle subgraphs with id and title in brackets without spaces', function() { + const res = flow.parser.parse('graph TD;A-->B;subgraph uid2[textofdoom];c-->d;end;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - const subgraphs = flow.parser.yy.getSubGraphs() - expect(subgraphs.length).toBe(1) - const subgraph = subgraphs[0] + const subgraphs = flow.parser.yy.getSubGraphs(); + expect(subgraphs.length).toBe(1); + const subgraph = subgraphs[0]; - expect(subgraph.title).toBe('textofdoom') - expect(subgraph.id).toBe('uid2') + expect(subgraph.title).toBe('textofdoom'); + expect(subgraph.id).toBe('uid2'); - expect(edges[0].type).toBe('arrow') - }) + expect(edges[0].type).toBe('arrow'); + }); - it('should handle subgraphs2', function () { - const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\n\n c-->d \nend\n') + it('should handle subgraphs2', function() { + const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\n\n c-->d \nend\n'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow') - }) + expect(edges[0].type).toBe('arrow'); + }); - it('should handle nested subgraphs', function () { - const str = 'graph TD\n' + - 'A-->B\n' + - 'subgraph myTitle\n\n' + - ' c-->d \n\n' + - ' subgraph inner\n\n e-->f \n end \n\n' + - ' subgraph inner\n\n h-->i \n end \n\n' + - 'end\n' - const res = flow.parser.parse(str) - }) + it('should handle nested subgraphs', function() { + const str = + 'graph TD\n' + + 'A-->B\n' + + 'subgraph myTitle\n\n' + + ' c-->d \n\n' + + ' subgraph inner\n\n e-->f \n end \n\n' + + ' subgraph inner\n\n h-->i \n end \n\n' + + 'end\n'; + const res = flow.parser.parse(str); + }); - it('should handle subgraphs4', function () { - const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-->d\nend;') + it('should handle subgraphs4', function() { + const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-->d\nend;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow') - }) + expect(edges[0].type).toBe('arrow'); + }); - it('should handle subgraphs5', function () { - const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-- text -->d\nd-->e\n end;') + it('should handle subgraphs5', function() { + const res = flow.parser.parse('graph TD\nA-->B\nsubgraph myTitle\nc-- text -->d\nd-->e\n end;'); - const vert = flow.parser.yy.getVertices() - const edges = flow.parser.yy.getEdges() + const vert = flow.parser.yy.getVertices(); + const edges = flow.parser.yy.getEdges(); - expect(edges[0].type).toBe('arrow') - }) - -}) + expect(edges[0].type).toBe('arrow'); + }); +}); From f9b30bdb4314e5d14c5f620f4aa2332412341ffb Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:58:32 -0700 Subject: [PATCH 11/13] #931 Reformatting for compliacne with code standard --- src/diagrams/class/classDb.js | 81 +++--- src/diagrams/class/classDiagram.spec.js | 349 ++++++++++++------------ src/diagrams/class/classRenderer.js | 323 ++++++++++------------ 3 files changed, 364 insertions(+), 389 deletions(-) diff --git a/src/diagrams/class/classDb.js b/src/diagrams/class/classDb.js index 227d95875..94ec0e21e 100644 --- a/src/diagrams/class/classDb.js +++ b/src/diagrams/class/classDb.js @@ -1,8 +1,7 @@ +import { logger } from '../../logger'; -import { logger } from '../../logger' - -let relations = [] -let classes = {} +let relations = []; +let classes = {}; /** * Function called by parser when a node definition has been found. @@ -11,75 +10,75 @@ let classes = {} * @param type * @param style */ -export const addClass = function (id) { +export const addClass = function(id) { if (typeof classes[id] === 'undefined') { classes[id] = { id: id, methods: [], members: [] - } + }; } -} +}; -export const clear = function () { - relations = [] - classes = {} -} +export const clear = function() { + relations = []; + classes = {}; +}; -export const getClass = function (id) { - return classes[id] -} -export const getClasses = function () { - return classes -} +export const getClass = function(id) { + return classes[id]; +}; +export const getClasses = function() { + return classes; +}; -export const getRelations = function () { - return relations -} +export const getRelations = function() { + return relations; +}; -export const addRelation = function (relation) { - logger.debug('Adding relation: ' + JSON.stringify(relation)) - addClass(relation.id1) - addClass(relation.id2) - relations.push(relation) -} +export const addRelation = function(relation) { + logger.debug('Adding relation: ' + JSON.stringify(relation)); + addClass(relation.id1); + addClass(relation.id2); + relations.push(relation); +}; -export const addMember = function (className, member) { - const theClass = classes[className] +export const addMember = function(className, member) { + const theClass = classes[className]; if (typeof member === 'string') { if (member.substr(-1) === ')') { - theClass.methods.push(member) + theClass.methods.push(member); } else { - theClass.members.push(member) + theClass.members.push(member); } } -} +}; -export const addMembers = function (className, MembersArr) { +export const addMembers = function(className, MembersArr) { if (Array.isArray(MembersArr)) { - MembersArr.forEach(member => addMember(className, member)) + MembersArr.forEach(member => addMember(className, member)); } -} +}; -export const cleanupLabel = function (label) { +export const cleanupLabel = function(label) { if (label.substring(0, 1) === ':') { - return label.substr(2).trim() + return label.substr(2).trim(); } else { - return label.trim() + return label.trim(); } -} +}; export const lineType = { LINE: 0, DOTTED_LINE: 1 -} +}; export const relationType = { AGGREGATION: 0, EXTENSION: 1, COMPOSITION: 2, DEPENDENCY: 3 -} +}; export default { addClass, @@ -93,4 +92,4 @@ export default { cleanupLabel, lineType, relationType -} +}; diff --git a/src/diagrams/class/classDiagram.spec.js b/src/diagrams/class/classDiagram.spec.js index 38657e11d..154898907 100644 --- a/src/diagrams/class/classDiagram.spec.js +++ b/src/diagrams/class/classDiagram.spec.js @@ -1,208 +1,211 @@ /* eslint-env jasmine */ -import { parser } from './parser/classDiagram' -import classDb from './classDb' +import { parser } from './parser/classDiagram'; +import classDb from './classDb'; -describe('class diagram, ', function () { - describe('when parsing an info graph it', function () { - beforeEach(function () { - parser.yy = classDb - }) +describe('class diagram, ', function() { + describe('when parsing an info graph it', function() { + beforeEach(function() { + parser.yy = classDb; + }); - it('should handle relation definitions', function () { - const str = 'classDiagram\n' + -'Class01 <|-- Class02\n' + -'Class03 *-- Class04\n' + -'Class05 o-- Class06\n' + -'Class07 .. Class08\n' + -'Class09 -- Class1' + it('should handle relation definitions', function() { + const str = + 'classDiagram\n' + + 'Class01 <|-- Class02\n' + + 'Class03 *-- Class04\n' + + 'Class05 o-- Class06\n' + + 'Class07 .. Class08\n' + + 'Class09 -- Class1'; - parser.parse(str) - }) - it('should handle relation definition of different types and directions', function () { - const str = 'classDiagram\n' + -'Class11 <|.. Class12\n' + -'Class13 --> Class14\n' + -'Class15 ..> Class16\n' + -'Class17 ..|> Class18\n' + -'Class19 <--* Class20' + parser.parse(str); + }); + it('should handle relation definition of different types and directions', function() { + const str = + 'classDiagram\n' + + 'Class11 <|.. Class12\n' + + 'Class13 --> Class14\n' + + 'Class15 ..> Class16\n' + + 'Class17 ..|> Class18\n' + + 'Class19 <--* Class20'; - parser.parse(str) - }) + parser.parse(str); + }); - it('should handle cardinality and labels', function () { - const str = 'classDiagram\n' + -'Class01 "1" *-- "many" Class02 : contains\n' + -'Class03 o-- Class04 : aggregation\n' + -'Class05 --> "1" Class06' + it('should handle cardinality and labels', function() { + const str = + 'classDiagram\n' + + 'Class01 "1" *-- "many" Class02 : contains\n' + + 'Class03 o-- Class04 : aggregation\n' + + 'Class05 --> "1" Class06'; - parser.parse(str) - }) - it('should handle class definitions', function () { - const str = 'classDiagram\n' + -'class Car\n' + -'Driver -- Car : drives >\n' + -'Car *-- Wheel : have 4 >\n' + -'Car -- Person : < owns' + parser.parse(str); + }); + it('should handle class definitions', function() { + const str = + 'classDiagram\n' + + 'class Car\n' + + 'Driver -- Car : drives >\n' + + 'Car *-- Wheel : have 4 >\n' + + 'Car -- Person : < owns'; - parser.parse(str) - }) + parser.parse(str); + }); - it('should handle method statements', function () { - const str = 'classDiagram\n' + -'Object <|-- ArrayList\n' + -'Object : equals()\n' + -'ArrayList : Object[] elementData\n' + -'ArrayList : size()' + it('should handle method statements', function() { + const str = + 'classDiagram\n' + + 'Object <|-- ArrayList\n' + + 'Object : equals()\n' + + 'ArrayList : Object[] elementData\n' + + 'ArrayList : size()'; - parser.parse(str) - }) - it('should handle parsing of method statements grouped by brackets', function () { - const str = 'classDiagram\n' + -'class Dummy {\n' + -'String data\n' + -' void methods()\n' + -'}\n' + -'\n' + -'class Flight {\n' + -' flightNumber : Integer\n' + -' departureTime : Date\n' + -'}' + parser.parse(str); + }); + it('should handle parsing of method statements grouped by brackets', function() { + const str = + 'classDiagram\n' + + 'class Dummy {\n' + + 'String data\n' + + ' void methods()\n' + + '}\n' + + '\n' + + 'class Flight {\n' + + ' flightNumber : Integer\n' + + ' departureTime : Date\n' + + '}'; - parser.parse(str) - }) + parser.parse(str); + }); - it('should handle parsing of separators', function () { - const str = 'classDiagram\n' + - 'class Foo1 {\n' + - ' You can use\n' + - ' several lines\n' + - '..\n' + - 'as you want\n' + - 'and group\n' + - '==\n' + - 'things together.\n' + - '__\n' + - 'You can have as many groups\n' + - 'as you want\n' + - '--\n' + - 'End of class\n' + - '}\n' + - '\n' + - 'class User {\n' + - '.. Simple Getter ..\n' + - '+ getName()\n' + - '+ getAddress()\n' + - '.. Some setter ..\n' + - '+ setName()\n' + - '__ private data __\n' + - 'int age\n' + - '-- encrypted --\n' + - 'String password\n' + - '}' + it('should handle parsing of separators', function() { + const str = + 'classDiagram\n' + + 'class Foo1 {\n' + + ' You can use\n' + + ' several lines\n' + + '..\n' + + 'as you want\n' + + 'and group\n' + + '==\n' + + 'things together.\n' + + '__\n' + + 'You can have as many groups\n' + + 'as you want\n' + + '--\n' + + 'End of class\n' + + '}\n' + + '\n' + + 'class User {\n' + + '.. Simple Getter ..\n' + + '+ getName()\n' + + '+ getAddress()\n' + + '.. Some setter ..\n' + + '+ setName()\n' + + '__ private data __\n' + + 'int age\n' + + '-- encrypted --\n' + + 'String password\n' + + '}'; - parser.parse(str) - }) - }) + parser.parse(str); + }); + }); - describe('when fetching data from an classDiagram graph it', function () { - beforeEach(function () { - parser.yy = classDb - parser.yy.clear() - }) - it('should handle relation definitions EXTENSION', function () { - const str = 'classDiagram\n' + - 'Class01 <|-- Class02' + describe('when fetching data from an classDiagram graph it', function() { + beforeEach(function() { + parser.yy = classDb; + parser.yy.clear(); + }); + it('should handle relation definitions EXTENSION', function() { + const str = 'classDiagram\n' + 'Class01 <|-- Class02'; - parser.parse(str) + parser.parse(str); - const relations = parser.yy.getRelations() + const relations = parser.yy.getRelations(); - expect(parser.yy.getClass('Class01').id).toBe('Class01') - expect(parser.yy.getClass('Class02').id).toBe('Class02') - expect(relations[0].relation.type1).toBe(classDb.relationType.EXTENSION) - expect(relations[0].relation.type2).toBe('none') - expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE) - }) - it('should handle relation definitions AGGREGATION and dotted line', function () { - const str = 'classDiagram\n' + - 'Class01 o.. Class02' + expect(parser.yy.getClass('Class01').id).toBe('Class01'); + expect(parser.yy.getClass('Class02').id).toBe('Class02'); + expect(relations[0].relation.type1).toBe(classDb.relationType.EXTENSION); + expect(relations[0].relation.type2).toBe('none'); + expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE); + }); + it('should handle relation definitions AGGREGATION and dotted line', function() { + const str = 'classDiagram\n' + 'Class01 o.. Class02'; - parser.parse(str) + parser.parse(str); - const relations = parser.yy.getRelations() + const relations = parser.yy.getRelations(); - expect(parser.yy.getClass('Class01').id).toBe('Class01') - expect(parser.yy.getClass('Class02').id).toBe('Class02') - expect(relations[0].relation.type1).toBe(classDb.relationType.AGGREGATION) - expect(relations[0].relation.type2).toBe('none') - expect(relations[0].relation.lineType).toBe(classDb.lineType.DOTTED_LINE) - }) - it('should handle relation definitions COMPOSITION on both sides', function () { - const str = 'classDiagram\n' + - 'Class01 *--* Class02' + expect(parser.yy.getClass('Class01').id).toBe('Class01'); + expect(parser.yy.getClass('Class02').id).toBe('Class02'); + expect(relations[0].relation.type1).toBe(classDb.relationType.AGGREGATION); + expect(relations[0].relation.type2).toBe('none'); + expect(relations[0].relation.lineType).toBe(classDb.lineType.DOTTED_LINE); + }); + it('should handle relation definitions COMPOSITION on both sides', function() { + const str = 'classDiagram\n' + 'Class01 *--* Class02'; - parser.parse(str) + parser.parse(str); - const relations = parser.yy.getRelations() + const relations = parser.yy.getRelations(); - expect(parser.yy.getClass('Class01').id).toBe('Class01') - expect(parser.yy.getClass('Class02').id).toBe('Class02') - expect(relations[0].relation.type1).toBe(classDb.relationType.COMPOSITION) - expect(relations[0].relation.type2).toBe(classDb.relationType.COMPOSITION) - expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE) - }) - it('should handle relation definitions no types', function () { - const str = 'classDiagram\n' + - 'Class01 -- Class02' + expect(parser.yy.getClass('Class01').id).toBe('Class01'); + expect(parser.yy.getClass('Class02').id).toBe('Class02'); + expect(relations[0].relation.type1).toBe(classDb.relationType.COMPOSITION); + expect(relations[0].relation.type2).toBe(classDb.relationType.COMPOSITION); + expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE); + }); + it('should handle relation definitions no types', function() { + const str = 'classDiagram\n' + 'Class01 -- Class02'; - parser.parse(str) + parser.parse(str); - const relations = parser.yy.getRelations() + const relations = parser.yy.getRelations(); - expect(parser.yy.getClass('Class01').id).toBe('Class01') - expect(parser.yy.getClass('Class02').id).toBe('Class02') - expect(relations[0].relation.type1).toBe('none') - expect(relations[0].relation.type2).toBe('none') - expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE) - }) - it('should handle relation definitions with type only on right side', function () { - const str = 'classDiagram\n' + - 'Class01 --|> Class02' + expect(parser.yy.getClass('Class01').id).toBe('Class01'); + expect(parser.yy.getClass('Class02').id).toBe('Class02'); + expect(relations[0].relation.type1).toBe('none'); + expect(relations[0].relation.type2).toBe('none'); + expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE); + }); + it('should handle relation definitions with type only on right side', function() { + const str = 'classDiagram\n' + 'Class01 --|> Class02'; - parser.parse(str) + parser.parse(str); - const relations = parser.yy.getRelations() + const relations = parser.yy.getRelations(); - expect(parser.yy.getClass('Class01').id).toBe('Class01') - expect(parser.yy.getClass('Class02').id).toBe('Class02') - expect(relations[0].relation.type1).toBe('none') - expect(relations[0].relation.type2).toBe(classDb.relationType.EXTENSION) - expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE) - }) + expect(parser.yy.getClass('Class01').id).toBe('Class01'); + expect(parser.yy.getClass('Class02').id).toBe('Class02'); + expect(relations[0].relation.type1).toBe('none'); + expect(relations[0].relation.type2).toBe(classDb.relationType.EXTENSION); + expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE); + }); - it('should handle multiple classes and relation definitions', function () { - const str = 'classDiagram\n' + - 'Class01 <|-- Class02\n' + - 'Class03 *-- Class04\n' + - 'Class05 o-- Class06\n' + - 'Class07 .. Class08\n' + - 'Class09 -- Class10' + it('should handle multiple classes and relation definitions', function() { + const str = + 'classDiagram\n' + + 'Class01 <|-- Class02\n' + + 'Class03 *-- Class04\n' + + 'Class05 o-- Class06\n' + + 'Class07 .. Class08\n' + + 'Class09 -- Class10'; - parser.parse(str) + parser.parse(str); - const relations = parser.yy.getRelations() + const relations = parser.yy.getRelations(); - expect(parser.yy.getClass('Class01').id).toBe('Class01') - expect(parser.yy.getClass('Class10').id).toBe('Class10') + expect(parser.yy.getClass('Class01').id).toBe('Class01'); + expect(parser.yy.getClass('Class10').id).toBe('Class10'); - expect(relations.length).toBe(5) + expect(relations.length).toBe(5); - expect(relations[0].relation.type1).toBe(classDb.relationType.EXTENSION) - expect(relations[0].relation.type2).toBe('none') - expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE) - expect(relations[3].relation.type1).toBe('none') - expect(relations[3].relation.type2).toBe('none') - expect(relations[3].relation.lineType).toBe(classDb.lineType.DOTTED_LINE) - }) - }) -}) + expect(relations[0].relation.type1).toBe(classDb.relationType.EXTENSION); + expect(relations[0].relation.type2).toBe('none'); + expect(relations[0].relation.lineType).toBe(classDb.lineType.LINE); + expect(relations[3].relation.type1).toBe('none'); + expect(relations[3].relation.type2).toBe('none'); + expect(relations[3].relation.lineType).toBe(classDb.lineType.DOTTED_LINE); + }); + }); +}); diff --git a/src/diagrams/class/classRenderer.js b/src/diagrams/class/classRenderer.js index a64bae1be..37a6629ae 100644 --- a/src/diagrams/class/classRenderer.js +++ b/src/diagrams/class/classRenderer.js @@ -1,38 +1,38 @@ -import * as d3 from 'd3' -import dagre from 'dagre-layout' -import graphlib from 'graphlibrary' -import { logger } from '../../logger' -import classDb from './classDb' -import { parser } from './parser/classDiagram' +import * as d3 from 'd3'; +import dagre from 'dagre-layout'; +import graphlib from 'graphlibrary'; +import { logger } from '../../logger'; +import classDb from './classDb'; +import { parser } from './parser/classDiagram'; -parser.yy = classDb +parser.yy = classDb; -const idCache = {} +const idCache = {}; -let classCnt = 0 +let classCnt = 0; const conf = { dividerMargin: 10, padding: 5, textHeight: 10 -} +}; // Todo optimize -const getGraphId = function (label) { - const keys = Object.keys(idCache) +const getGraphId = function(label) { + const keys = Object.keys(idCache); for (let i = 0; i < keys.length; i++) { if (idCache[keys[i]].label === label) { - return keys[i] + return keys[i]; } } - return undefined -} + return undefined; +}; /** * Setup arrow head and define the marker. The result is appended to the svg. */ -const insertMarkers = function (elem) { +const insertMarkers = function(elem) { elem .append('defs') .append('marker') @@ -44,7 +44,7 @@ const insertMarkers = function (elem) { .attr('markerHeight', 240) .attr('orient', 'auto') .append('path') - .attr('d', 'M 1,7 L18,13 V 1 Z') + .attr('d', 'M 1,7 L18,13 V 1 Z'); elem .append('defs') @@ -56,7 +56,7 @@ const insertMarkers = function (elem) { .attr('markerHeight', 28) .attr('orient', 'auto') .append('path') - .attr('d', 'M 1,1 V 13 L18,7 Z') // this is actual shape for arrowhead + .attr('d', 'M 1,1 V 13 L18,7 Z'); // this is actual shape for arrowhead elem .append('defs') @@ -69,7 +69,7 @@ const insertMarkers = function (elem) { .attr('markerHeight', 240) .attr('orient', 'auto') .append('path') - .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z') + .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z'); elem .append('defs') @@ -81,7 +81,7 @@ const insertMarkers = function (elem) { .attr('markerHeight', 28) .attr('orient', 'auto') .append('path') - .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z') + .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z'); elem .append('defs') @@ -94,7 +94,7 @@ const insertMarkers = function (elem) { .attr('markerHeight', 240) .attr('orient', 'auto') .append('path') - .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z') + .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z'); elem .append('defs') @@ -106,7 +106,7 @@ const insertMarkers = function (elem) { .attr('markerHeight', 28) .attr('orient', 'auto') .append('path') - .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z') + .attr('d', 'M 18,7 L9,13 L1,7 L9,1 Z'); elem .append('defs') @@ -119,7 +119,7 @@ const insertMarkers = function (elem) { .attr('markerHeight', 240) .attr('orient', 'auto') .append('path') - .attr('d', 'M 5,7 L9,13 L1,7 L9,1 Z') + .attr('d', 'M 5,7 L9,13 L1,7 L9,1 Z'); elem .append('defs') @@ -131,96 +131,86 @@ const insertMarkers = function (elem) { .attr('markerHeight', 28) .attr('orient', 'auto') .append('path') - .attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z') -} + .attr('d', 'M 18,7 L9,13 L14,7 L9,1 Z'); +}; -let edgeCount = 0 -let total = 0 -const drawEdge = function (elem, path, relation) { - const getRelationType = function (type) { +let edgeCount = 0; +let total = 0; +const drawEdge = function(elem, path, relation) { + const getRelationType = function(type) { switch (type) { case classDb.relationType.AGGREGATION: - return 'aggregation' + return 'aggregation'; case classDb.relationType.EXTENSION: - return 'extension' + return 'extension'; case classDb.relationType.COMPOSITION: - return 'composition' + return 'composition'; case classDb.relationType.DEPENDENCY: - return 'dependency' + return 'dependency'; } - } + }; - path.points = path.points.filter(p => !Number.isNaN(p.y)) + path.points = path.points.filter(p => !Number.isNaN(p.y)); // The data for our line - const lineData = path.points + const lineData = path.points; // This is the accessor function we talked about above const lineFunction = d3 .line() - .x(function (d) { - return d.x + .x(function(d) { + return d.x; }) - .y(function (d) { - return d.y + .y(function(d) { + return d.y; }) - .curve(d3.curveBasis) + .curve(d3.curveBasis); const svgPath = elem .append('path') .attr('d', lineFunction(lineData)) .attr('id', 'edge' + edgeCount) - .attr('class', 'relation') - let url = '' + .attr('class', 'relation'); + let url = ''; if (conf.arrowMarkerAbsolute) { url = window.location.protocol + '//' + window.location.host + window.location.pathname + - window.location.search - url = url.replace(/\(/g, '\\(') - url = url.replace(/\)/g, '\\)') + window.location.search; + url = url.replace(/\(/g, '\\('); + url = url.replace(/\)/g, '\\)'); } if (relation.relation.type1 !== 'none') { svgPath.attr( 'marker-start', - 'url(' + - url + - '#' + - getRelationType(relation.relation.type1) + - 'Start' + - ')' - ) + 'url(' + url + '#' + getRelationType(relation.relation.type1) + 'Start' + ')' + ); } if (relation.relation.type2 !== 'none') { svgPath.attr( 'marker-end', - 'url(' + - url + - '#' + - getRelationType(relation.relation.type2) + - 'End' + - ')' - ) + 'url(' + url + '#' + getRelationType(relation.relation.type2) + 'End' + ')' + ); } - let x, y - const l = path.points.length + let x, y; + const l = path.points.length; if (l % 2 !== 0 && l > 1) { - const p1 = path.points[Math.floor(l / 2)] - const p2 = path.points[Math.ceil(l / 2)] - x = (p1.x + p2.x) / 2 - y = (p1.y + p2.y) / 2 + const p1 = path.points[Math.floor(l / 2)]; + const p2 = path.points[Math.ceil(l / 2)]; + x = (p1.x + p2.x) / 2; + y = (p1.y + p2.y) / 2; } else { - const p = path.points[Math.floor(l / 2)] - x = p.x - y = p.y + const p = path.points[Math.floor(l / 2)]; + x = p.x; + y = p.y; } if (typeof relation.title !== 'undefined') { - const g = elem.append('g').attr('class', 'classLabel') + const g = elem.append('g').attr('class', 'classLabel'); const label = g .append('text') .attr('class', 'label') @@ -228,189 +218,177 @@ const drawEdge = function (elem, path, relation) { .attr('y', y) .attr('fill', 'red') .attr('text-anchor', 'middle') - .text(relation.title) + .text(relation.title); - window.label = label - const bounds = label.node().getBBox() + window.label = label; + const bounds = label.node().getBBox(); g.insert('rect', ':first-child') .attr('class', 'box') .attr('x', bounds.x - conf.padding / 2) .attr('y', bounds.y - conf.padding / 2) .attr('width', bounds.width + conf.padding) - .attr('height', bounds.height + conf.padding) + .attr('height', bounds.height + conf.padding); } - edgeCount++ -} + edgeCount++; +}; -const drawClass = function (elem, classDef) { - logger.info('Rendering class ' + classDef) +const drawClass = function(elem, classDef) { + logger.info('Rendering class ' + classDef); - const addTspan = function (textEl, txt, isFirst) { + const addTspan = function(textEl, txt, isFirst) { const tSpan = textEl .append('tspan') .attr('x', conf.padding) - .text(txt) + .text(txt); if (!isFirst) { - tSpan.attr('dy', conf.textHeight) + tSpan.attr('dy', conf.textHeight); } - } + }; - const id = 'classId' + (classCnt % total) + const id = 'classId' + (classCnt % total); const classInfo = { id: id, label: classDef.id, width: 0, height: 0 - } + }; const g = elem .append('g') .attr('id', id) - .attr('class', 'classGroup') + .attr('class', 'classGroup'); const title = g .append('text') .attr('x', conf.padding) .attr('y', conf.textHeight + conf.padding) - .text(classDef.id) + .text(classDef.id); - const titleHeight = title.node().getBBox().height + const titleHeight = title.node().getBBox().height; const membersLine = g .append('line') // text label for the x axis .attr('x1', 0) .attr('y1', conf.padding + titleHeight + conf.dividerMargin / 2) - .attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2) + .attr('y2', conf.padding + titleHeight + conf.dividerMargin / 2); const members = g .append('text') // text label for the x axis .attr('x', conf.padding) .attr('y', titleHeight + conf.dividerMargin + conf.textHeight) .attr('fill', 'white') - .attr('class', 'classText') + .attr('class', 'classText'); - let isFirst = true - classDef.members.forEach(function (member) { - addTspan(members, member, isFirst) - isFirst = false - }) + let isFirst = true; + classDef.members.forEach(function(member) { + addTspan(members, member, isFirst); + isFirst = false; + }); - const membersBox = members.node().getBBox() + const membersBox = members.node().getBBox(); const methodsLine = g .append('line') // text label for the x axis .attr('x1', 0) - .attr( - 'y1', - conf.padding + titleHeight + conf.dividerMargin + membersBox.height - ) - .attr( - 'y2', - conf.padding + titleHeight + conf.dividerMargin + membersBox.height - ) + .attr('y1', conf.padding + titleHeight + conf.dividerMargin + membersBox.height) + .attr('y2', conf.padding + titleHeight + conf.dividerMargin + membersBox.height); const methods = g .append('text') // text label for the x axis .attr('x', conf.padding) - .attr( - 'y', - titleHeight + 2 * conf.dividerMargin + membersBox.height + conf.textHeight - ) + .attr('y', titleHeight + 2 * conf.dividerMargin + membersBox.height + conf.textHeight) .attr('fill', 'white') - .attr('class', 'classText') + .attr('class', 'classText'); - isFirst = true + isFirst = true; - classDef.methods.forEach(function (method) { - addTspan(methods, method, isFirst) - isFirst = false - }) + classDef.methods.forEach(function(method) { + addTspan(methods, method, isFirst); + isFirst = false; + }); - const classBox = g.node().getBBox() + const classBox = g.node().getBBox(); g.insert('rect', ':first-child') .attr('x', 0) .attr('y', 0) .attr('width', classBox.width + 2 * conf.padding) - .attr('height', classBox.height + conf.padding + 0.5 * conf.dividerMargin) + .attr('height', classBox.height + conf.padding + 0.5 * conf.dividerMargin); - membersLine.attr('x2', classBox.width + 2 * conf.padding) - methodsLine.attr('x2', classBox.width + 2 * conf.padding) + membersLine.attr('x2', classBox.width + 2 * conf.padding); + methodsLine.attr('x2', classBox.width + 2 * conf.padding); - classInfo.width = classBox.width + 2 * conf.padding - classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin + classInfo.width = classBox.width + 2 * conf.padding; + classInfo.height = classBox.height + conf.padding + 0.5 * conf.dividerMargin; - idCache[id] = classInfo - classCnt++ - return classInfo -} + idCache[id] = classInfo; + classCnt++; + return classInfo; +}; -export const setConf = function (cnf) { - const keys = Object.keys(cnf) +export const setConf = function(cnf) { + const keys = Object.keys(cnf); - keys.forEach(function (key) { - conf[key] = cnf[key] - }) -} + keys.forEach(function(key) { + conf[key] = cnf[key]; + }); +}; /** * Draws a flowchart in the tag with id: id based on the graph definition in text. * @param text * @param id */ -export const draw = function (text, id) { - parser.yy.clear() - parser.parse(text) +export const draw = function(text, id) { + parser.yy.clear(); + parser.parse(text); - logger.info('Rendering diagram ' + text) + logger.info('Rendering diagram ' + text); /// / Fetch the default direction, use TD if none was found - const diagram = d3.select(`[id='${id}']`) - insertMarkers(diagram) + const diagram = d3.select(`[id='${id}']`); + insertMarkers(diagram); // Layout graph, Create a new directed graph const g = new graphlib.Graph({ multigraph: true - }) + }); // Set an object for the graph label g.setGraph({ isMultiGraph: true - }) + }); // Default to assigning a new object as a label for each new edge. - g.setDefaultEdgeLabel(function () { - return {} - }) + g.setDefaultEdgeLabel(function() { + return {}; + }); - const classes = classDb.getClasses() - const keys = Object.keys(classes) - total = keys.length + const classes = classDb.getClasses(); + const keys = Object.keys(classes); + total = keys.length; for (let i = 0; i < keys.length; i++) { - const classDef = classes[keys[i]] - const node = drawClass(diagram, classDef) + const classDef = classes[keys[i]]; + const node = drawClass(diagram, classDef); // Add nodes to the graph. The first argument is the node id. The second is // metadata about the node. In this case we're going to add labels to each of // our nodes. - g.setNode(node.id, node) - logger.info('Org height: ' + node.height) + g.setNode(node.id, node); + logger.info('Org height: ' + node.height); } - const relations = classDb.getRelations() - relations.forEach(function (relation) { + const relations = classDb.getRelations(); + relations.forEach(function(relation) { logger.info( - 'tjoho' + - getGraphId(relation.id1) + - getGraphId(relation.id2) + - JSON.stringify(relation) - ) + 'tjoho' + getGraphId(relation.id1) + getGraphId(relation.id2) + JSON.stringify(relation) + ); g.setEdge(getGraphId(relation.id1), getGraphId(relation.id2), { relation: relation - }) - }) - dagre.layout(g) - g.nodes().forEach(function (v) { + }); + }); + dagre.layout(g); + g.nodes().forEach(function(v) { if (typeof v !== 'undefined' && typeof g.node(v) !== 'undefined') { - logger.debug('Node ' + v + ': ' + JSON.stringify(g.node(v))) + logger.debug('Node ' + v + ': ' + JSON.stringify(g.node(v))); d3.select('#' + v).attr( 'transform', 'translate(' + @@ -418,27 +396,22 @@ export const draw = function (text, id) { ',' + (g.node(v).y - g.node(v).height / 2) + ' )' - ) + ); } - }) - g.edges().forEach(function (e) { + }); + g.edges().forEach(function(e) { if (typeof e !== 'undefined' && typeof g.edge(e) !== 'undefined') { - logger.debug( - 'Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(g.edge(e)) - ) - drawEdge(diagram, g.edge(e), g.edge(e).relation) + logger.debug('Edge ' + e.v + ' -> ' + e.w + ': ' + JSON.stringify(g.edge(e))); + drawEdge(diagram, g.edge(e), g.edge(e).relation); } - }) + }); - diagram.attr('height', '100%') - diagram.attr('width', '100%') - diagram.attr( - 'viewBox', - '0 0 ' + (g.graph().width + 20) + ' ' + (g.graph().height + 20) - ) -} + diagram.attr('height', '100%'); + diagram.attr('width', '100%'); + diagram.attr('viewBox', '0 0 ' + (g.graph().width + 20) + ' ' + (g.graph().height + 20)); +}; export default { setConf, draw -} +}; From 0e8164d805499e618c367a4655187587c2c15c61 Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:58:57 -0700 Subject: [PATCH 12/13] #931 Compliacne with code standard --- src/config.js | 23 ++++++++-------- src/logger.js | 38 ++++++++++++------------- src/utils.js | 44 ++++++++++++++--------------- src/utils.spec.js | 70 +++++++++++++++++++++++------------------------ 4 files changed, 87 insertions(+), 88 deletions(-) diff --git a/src/config.js b/src/config.js index d288155ce..0b5df6e0c 100644 --- a/src/config.js +++ b/src/config.js @@ -1,28 +1,27 @@ -let config = { -} +let config = {}; -const setConf = function (cnf) { +const setConf = function(cnf) { // Top level initially mermaid, gflow, sequenceDiagram and gantt - const lvl1Keys = Object.keys(cnf) + const lvl1Keys = Object.keys(cnf); for (let i = 0; i < lvl1Keys.length; i++) { if (typeof cnf[lvl1Keys[i]] === 'object' && cnf[lvl1Keys[i]] != null) { - const lvl2Keys = Object.keys(cnf[lvl1Keys[i]]) + const lvl2Keys = Object.keys(cnf[lvl1Keys[i]]); for (let j = 0; j < lvl2Keys.length; j++) { // logger.debug('Setting conf ', lvl1Keys[i], '-', lvl2Keys[j]) if (typeof config[lvl1Keys[i]] === 'undefined') { - config[lvl1Keys[i]] = {} + config[lvl1Keys[i]] = {}; } // logger.debug('Setting config: ' + lvl1Keys[i] + ' ' + lvl2Keys[j] + ' to ' + cnf[lvl1Keys[i]][lvl2Keys[j]]) - config[lvl1Keys[i]][lvl2Keys[j]] = cnf[lvl1Keys[i]][lvl2Keys[j]] + config[lvl1Keys[i]][lvl2Keys[j]] = cnf[lvl1Keys[i]][lvl2Keys[j]]; } } else { - config[lvl1Keys[i]] = cnf[lvl1Keys[i]] + config[lvl1Keys[i]] = cnf[lvl1Keys[i]]; } } -} +}; export const setConfig = conf => { - setConf(conf) -} -export const getConfig = () => config + setConf(conf); +}; +export const getConfig = () => config; diff --git a/src/logger.js b/src/logger.js index eefaccf34..5de9e320a 100644 --- a/src/logger.js +++ b/src/logger.js @@ -1,4 +1,4 @@ -import moment from 'moment-mini' +import moment from 'moment-mini'; export const LEVELS = { debug: 1, @@ -6,7 +6,7 @@ export const LEVELS = { warn: 3, error: 4, fatal: 5 -} +}; export const logger = { debug: () => {}, @@ -14,32 +14,32 @@ export const logger = { warn: () => {}, error: () => {}, fatal: () => {} -} +}; -export const setLogLevel = function (level) { - logger.debug = () => {} - logger.info = () => {} - logger.warn = () => {} - logger.error = () => {} - logger.fatal = () => {} +export const setLogLevel = function(level) { + logger.debug = () => {}; + logger.info = () => {}; + logger.warn = () => {}; + logger.error = () => {}; + logger.fatal = () => {}; if (level <= LEVELS.fatal) { - logger.fatal = console.log.bind(console, '\x1b[35m', format('FATAL')) + logger.fatal = console.log.bind(console, '\x1b[35m', format('FATAL')); } if (level <= LEVELS.error) { - logger.error = console.log.bind(console, '\x1b[31m', format('ERROR')) + logger.error = console.log.bind(console, '\x1b[31m', format('ERROR')); } if (level <= LEVELS.warn) { - logger.warn = console.log.bind(console, `\x1b[33m`, format('WARN')) + logger.warn = console.log.bind(console, `\x1b[33m`, format('WARN')); } if (level <= LEVELS.info) { - logger.info = console.log.bind(console, '\x1b[34m', format('INFO')) + logger.info = console.log.bind(console, '\x1b[34m', format('INFO')); } if (level <= LEVELS.debug) { - logger.debug = console.log.bind(console, '\x1b[32m', format('DEBUG')) + logger.debug = console.log.bind(console, '\x1b[32m', format('DEBUG')); } -} +}; -const format = (level) => { - const time = moment().format('HH:mm:ss.SSS') - return `${time} : ${level} : ` -} +const format = level => { + const time = moment().format('HH:mm:ss.SSS'); + return `${time} : ${level} : `; +}; diff --git a/src/utils.js b/src/utils.js index 462e7040c..357865fbf 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,5 @@ -import * as d3 from 'd3' -import { logger } from './logger' +import * as d3 from 'd3'; +import { logger } from './logger'; /** * @function detectType @@ -18,34 +18,34 @@ import { logger } from './logger' * @param {string} text The text defining the graph * @returns {string} A graph definition key */ -export const detectType = function (text) { - text = text.replace(/^\s*%%.*\n/g, '\n') - logger.debug('Detecting diagram type based on the text ' + text) +export const detectType = function(text) { + text = text.replace(/^\s*%%.*\n/g, '\n'); + logger.debug('Detecting diagram type based on the text ' + text); if (text.match(/^\s*sequenceDiagram/)) { - return 'sequence' + return 'sequence'; } if (text.match(/^\s*gantt/)) { - return 'gantt' + return 'gantt'; } if (text.match(/^\s*classDiagram/)) { - return 'class' + return 'class'; } if (text.match(/^\s*gitGraph/)) { - return 'git' + return 'git'; } if (text.match(/^\s*info/)) { - return 'info' + return 'info'; } if (text.match(/^\s*pie/)) { - return 'pie' + return 'pie'; } - return 'flowchart' -} + return 'flowchart'; +}; /** * @function isSubstringInArray @@ -54,23 +54,23 @@ export const detectType = function (text) { * @param {array} arr The array to search * @returns {number} the array index containing the substring or -1 if not present **/ -export const isSubstringInArray = function (str, arr) { +export const isSubstringInArray = function(str, arr) { for (let i = 0; i < arr.length; i++) { - if (arr[i].match(str)) return i + if (arr[i].match(str)) return i; } - return -1 -} + return -1; +}; export const interpolateToCurve = (interpolate, defaultCurve) => { if (!interpolate) { - return defaultCurve + return defaultCurve; } - const curveName = `curve${interpolate.charAt(0).toUpperCase() + interpolate.slice(1)}` - return d3[curveName] || defaultCurve -} + const curveName = `curve${interpolate.charAt(0).toUpperCase() + interpolate.slice(1)}`; + return d3[curveName] || defaultCurve; +}; export default { detectType, isSubstringInArray, interpolateToCurve -} +}; diff --git a/src/utils.spec.js b/src/utils.spec.js index 43341fb6d..86de39513 100644 --- a/src/utils.spec.js +++ b/src/utils.spec.js @@ -1,39 +1,39 @@ /* eslint-env jasmine */ -import utils from './utils' +import utils from './utils'; -describe('when detecting chart type ', function () { - it('should handle a graph defintion', function () { - const str = 'graph TB\nbfs1:queue' - const type = utils.detectType(str) - expect(type).toBe('flowchart') - }) - it('should handle a graph defintion with leading spaces', function () { - const str = ' graph TB\nbfs1:queue' - const type = utils.detectType(str) - expect(type).toBe('flowchart') - }) +describe('when detecting chart type ', function() { + it('should handle a graph defintion', function() { + const str = 'graph TB\nbfs1:queue'; + const type = utils.detectType(str); + expect(type).toBe('flowchart'); + }); + it('should handle a graph defintion with leading spaces', function() { + const str = ' graph TB\nbfs1:queue'; + const type = utils.detectType(str); + expect(type).toBe('flowchart'); + }); - it('should handle a graph defintion with leading spaces and newline', function () { - const str = ' \n graph TB\nbfs1:queue' - const type = utils.detectType(str) - expect(type).toBe('flowchart') - }) - it('should handle a graph defintion for gitGraph', function () { - const str = ' \n gitGraph TB:\nbfs1:queue' - const type = utils.detectType(str) - expect(type).toBe('git') - }) -}) + it('should handle a graph defintion with leading spaces and newline', function() { + const str = ' \n graph TB\nbfs1:queue'; + const type = utils.detectType(str); + expect(type).toBe('flowchart'); + }); + it('should handle a graph defintion for gitGraph', function() { + const str = ' \n gitGraph TB:\nbfs1:queue'; + const type = utils.detectType(str); + expect(type).toBe('git'); + }); +}); -describe('when finding substring in array ', function () { - it('should return the array index that contains the substring', function () { - const arr = ['stroke:val1', 'fill:val2'] - const result = utils.isSubstringInArray('fill', arr) - expect(result).toEqual(1) - }) - it('should return -1 if the substring is not found in the array', function () { - const arr = ['stroke:val1', 'stroke-width:val2'] - const result = utils.isSubstringInArray('fill', arr) - expect(result).toEqual(-1) - }) -}) +describe('when finding substring in array ', function() { + it('should return the array index that contains the substring', function() { + const arr = ['stroke:val1', 'fill:val2']; + const result = utils.isSubstringInArray('fill', arr); + expect(result).toEqual(1); + }); + it('should return -1 if the substring is not found in the array', function() { + const arr = ['stroke:val1', 'stroke-width:val2']; + const result = utils.isSubstringInArray('fill', arr); + expect(result).toEqual(-1); + }); +}); From 7e5802e79959bf3c5c4d33c98de8df13d69a7ecd Mon Sep 17 00:00:00 2001 From: knsv Date: Thu, 12 Sep 2019 12:59:13 -0700 Subject: [PATCH 13/13] #931 Last code standard fixes --- src/mermaid.js | 132 +++++++------ src/mermaid.spec.js | 320 +++++++++++++++--------------- src/mermaidAPI.js | 429 ++++++++++++++++++++++------------------- src/mermaidAPI.spec.js | 68 +++---- 4 files changed, 497 insertions(+), 452 deletions(-) diff --git a/src/mermaid.js b/src/mermaid.js index ebfc87532..76b644ef2 100644 --- a/src/mermaid.js +++ b/src/mermaid.js @@ -2,10 +2,10 @@ * Web page integration module for the mermaid framework. It uses the mermaidAPI for mermaid functionality and to render * the diagrams to svg code. */ -import he from 'he' +import he from 'he'; -import mermaidAPI from './mermaidAPI' -import { logger } from './logger' +import mermaidAPI from './mermaidAPI'; +import { logger } from './logger'; /** * ## init @@ -28,126 +28,142 @@ import { logger } from './logger' * Renders the mermaid diagrams * @param nodes a css selector or an array of nodes */ -const init = function () { - const conf = mermaidAPI.getConfig() - logger.debug('Starting rendering diagrams') - let nodes +const init = function() { + const conf = mermaidAPI.getConfig(); + logger.debug('Starting rendering diagrams'); + let nodes; if (arguments.length >= 2) { /*! sequence config was passed as #1 */ if (typeof arguments[0] !== 'undefined') { - mermaid.sequenceConfig = arguments[0] + mermaid.sequenceConfig = arguments[0]; } - nodes = arguments[1] + nodes = arguments[1]; } else { - nodes = arguments[0] + nodes = arguments[0]; } // if last argument is a function this is the callback function - let callback + let callback; if (typeof arguments[arguments.length - 1] === 'function') { - callback = arguments[arguments.length - 1] - logger.debug('Callback function found') + callback = arguments[arguments.length - 1]; + logger.debug('Callback function found'); } else { if (typeof conf.mermaid !== 'undefined') { if (typeof conf.mermaid.callback === 'function') { - callback = conf.mermaid.callback - logger.debug('Callback function found') + callback = conf.mermaid.callback; + logger.debug('Callback function found'); } else { - logger.debug('No Callback function found') + logger.debug('No Callback function found'); } } } - nodes = nodes === undefined ? document.querySelectorAll('.mermaid') - : typeof nodes === 'string' ? document.querySelectorAll(nodes) - : nodes instanceof window.Node ? [nodes] - : nodes // Last case - sequence config was passed pick next + nodes = + nodes === undefined + ? document.querySelectorAll('.mermaid') + : typeof nodes === 'string' + ? document.querySelectorAll(nodes) + : nodes instanceof window.Node + ? [nodes] + : nodes; // Last case - sequence config was passed pick next - logger.debug('Start On Load before: ' + mermaid.startOnLoad) + logger.debug('Start On Load before: ' + mermaid.startOnLoad); if (typeof mermaid.startOnLoad !== 'undefined') { - logger.debug('Start On Load inner: ' + mermaid.startOnLoad) - mermaidAPI.initialize({ startOnLoad: mermaid.startOnLoad }) + logger.debug('Start On Load inner: ' + mermaid.startOnLoad); + mermaidAPI.initialize({ startOnLoad: mermaid.startOnLoad }); } if (typeof mermaid.ganttConfig !== 'undefined') { - mermaidAPI.initialize({ gantt: mermaid.ganttConfig }) + mermaidAPI.initialize({ gantt: mermaid.ganttConfig }); } - let txt + let txt; for (let i = 0; i < nodes.length; i++) { - const element = nodes[i] + const element = nodes[i]; /*! Check if previously processed */ if (!element.getAttribute('data-processed')) { - element.setAttribute('data-processed', true) + element.setAttribute('data-processed', true); } else { - continue + continue; } - const id = `mermaid-${Date.now()}` + const id = `mermaid-${Date.now()}`; // Fetch the graph definition including tags - txt = element.innerHTML + txt = element.innerHTML; // transforms the html to pure text - txt = he.decode(txt).trim().replace(/
/ig, '
') + txt = he + .decode(txt) + .trim() + .replace(/
/gi, '
'); - mermaidAPI.render(id, txt, (svgCode, bindFunctions) => { - element.innerHTML = svgCode - if (typeof callback !== 'undefined') { - callback(id) - } - if (bindFunctions) bindFunctions(element) - }, element) + mermaidAPI.render( + id, + txt, + (svgCode, bindFunctions) => { + element.innerHTML = svgCode; + if (typeof callback !== 'undefined') { + callback(id); + } + if (bindFunctions) bindFunctions(element); + }, + element + ); } -} +}; -const initialize = function (config) { - logger.debug('Initializing mermaid ') +const initialize = function(config) { + logger.debug('Initializing mermaid '); if (typeof config.mermaid !== 'undefined') { if (typeof config.mermaid.startOnLoad !== 'undefined') { - mermaid.startOnLoad = config.mermaid.startOnLoad + mermaid.startOnLoad = config.mermaid.startOnLoad; } if (typeof config.mermaid.htmlLabels !== 'undefined') { - mermaid.htmlLabels = config.mermaid.htmlLabels + mermaid.htmlLabels = config.mermaid.htmlLabels; } } - mermaidAPI.initialize(config) -} + mermaidAPI.initialize(config); +}; /** * ##contentLoaded * Callback function that is called when page is loaded. This functions fetches configuration for mermaid rendering and * calls init for rendering the mermaid diagrams on the page. */ -const contentLoaded = function () { - let config +const contentLoaded = function() { + let config; if (mermaid.startOnLoad) { // No config found, do check API config - config = mermaidAPI.getConfig() + config = mermaidAPI.getConfig(); if (config.startOnLoad) { - mermaid.init() + mermaid.init(); } } else { if (typeof mermaid.startOnLoad === 'undefined') { - logger.debug('In start, no config') - config = mermaidAPI.getConfig() + logger.debug('In start, no config'); + config = mermaidAPI.getConfig(); if (config.startOnLoad) { - mermaid.init() + mermaid.init(); } } } -} +}; if (typeof document !== 'undefined') { /*! * Wait for document loaded before starting the execution */ - window.addEventListener('load', function () { - contentLoaded() - }, false) + window.addEventListener( + 'load', + function() { + contentLoaded(); + }, + false + ); } const mermaid = { @@ -162,6 +178,6 @@ const mermaid = { initialize, contentLoaded -} +}; -export default mermaid +export default mermaid; diff --git a/src/mermaid.spec.js b/src/mermaid.spec.js index 996ad21f5..8bfbc1995 100644 --- a/src/mermaid.spec.js +++ b/src/mermaid.spec.js @@ -1,195 +1,200 @@ /* eslint-env jasmine */ -import mermaid from './mermaid' -import flowDb from './diagrams/flowchart/flowDb' -import flowParser from './diagrams/flowchart/parser/flow' -import flowRenderer from './diagrams/flowchart/flowRenderer' +import mermaid from './mermaid'; +import flowDb from './diagrams/flowchart/flowDb'; +import flowParser from './diagrams/flowchart/parser/flow'; +import flowRenderer from './diagrams/flowchart/flowRenderer'; -describe('when using mermaid and ', function () { - describe('when detecting chart type ', function () { - it('should not start rendering with mermaid.startOnLoad set to false', function () { - mermaid.startOnLoad = false - document.body.innerHTML = '
graph TD;\na;
' - spyOn(mermaid, 'init') - mermaid.contentLoaded() - expect(mermaid.init).not.toHaveBeenCalled() - }) +describe('when using mermaid and ', function() { + describe('when detecting chart type ', function() { + it('should not start rendering with mermaid.startOnLoad set to false', function() { + mermaid.startOnLoad = false; + document.body.innerHTML = '
graph TD;\na;
'; + spyOn(mermaid, 'init'); + mermaid.contentLoaded(); + expect(mermaid.init).not.toHaveBeenCalled(); + }); - it('should start rendering with both startOnLoad set', function () { - mermaid.startOnLoad = true - document.body.innerHTML = '
graph TD;\na;
' - spyOn(mermaid, 'init') - mermaid.contentLoaded() - expect(mermaid.init).toHaveBeenCalled() - }) + it('should start rendering with both startOnLoad set', function() { + mermaid.startOnLoad = true; + document.body.innerHTML = '
graph TD;\na;
'; + spyOn(mermaid, 'init'); + mermaid.contentLoaded(); + expect(mermaid.init).toHaveBeenCalled(); + }); - it('should start rendering with mermaid.startOnLoad', function () { - mermaid.startOnLoad = true - document.body.innerHTML = '
graph TD;\na;
' - spyOn(mermaid, 'init') - mermaid.contentLoaded() - expect(mermaid.init).toHaveBeenCalled() - }) + it('should start rendering with mermaid.startOnLoad', function() { + mermaid.startOnLoad = true; + document.body.innerHTML = '
graph TD;\na;
'; + spyOn(mermaid, 'init'); + mermaid.contentLoaded(); + expect(mermaid.init).toHaveBeenCalled(); + }); - it('should start rendering as a default with no changes performed', function () { - document.body.innerHTML = '
graph TD;\na;
' - spyOn(mermaid, 'init') - mermaid.contentLoaded() - expect(mermaid.init).toHaveBeenCalled() - }) - }) + it('should start rendering as a default with no changes performed', function() { + document.body.innerHTML = '
graph TD;\na;
'; + spyOn(mermaid, 'init'); + mermaid.contentLoaded(); + expect(mermaid.init).toHaveBeenCalled(); + }); + }); - describe('when calling addEdges ', function () { - beforeEach(function () { - flowParser.parser.yy = flowDb - flowDb.clear() - }) - it('it should handle edges with text', function () { - flowParser.parser.parse('graph TD;A-->|text ex|B;') - flowParser.parser.yy.getVertices() - const edges = flowParser.parser.yy.getEdges() + describe('when calling addEdges ', function() { + beforeEach(function() { + flowParser.parser.yy = flowDb; + flowDb.clear(); + }); + it('it should handle edges with text', function() { + flowParser.parser.parse('graph TD;A-->|text ex|B;'); + flowParser.parser.yy.getVertices(); + const edges = flowParser.parser.yy.getEdges(); const mockG = { - setEdge: function (start, end, options) { - expect(start).toBe('A') - expect(end).toBe('B') - expect(options.arrowhead).toBe('normal') - expect(options.label.match('text ex')).toBeTruthy() + setEdge: function(start, end, options) { + expect(start).toBe('A'); + expect(end).toBe('B'); + expect(options.arrowhead).toBe('normal'); + expect(options.label.match('text ex')).toBeTruthy(); } - } + }; - flowRenderer.addEdges(edges, mockG) - }) + flowRenderer.addEdges(edges, mockG); + }); - it('should handle edges without text', function () { - flowParser.parser.parse('graph TD;A-->B;') - flowParser.parser.yy.getVertices() - const edges = flowParser.parser.yy.getEdges() + it('should handle edges without text', function() { + flowParser.parser.parse('graph TD;A-->B;'); + flowParser.parser.yy.getVertices(); + const edges = flowParser.parser.yy.getEdges(); const mockG = { - setEdge: function (start, end, options) { - expect(start).toBe('A') - expect(end).toBe('B') - expect(options.arrowhead).toBe('normal') + setEdge: function(start, end, options) { + expect(start).toBe('A'); + expect(end).toBe('B'); + expect(options.arrowhead).toBe('normal'); } - } + }; - flowRenderer.addEdges(edges, mockG) - }) + flowRenderer.addEdges(edges, mockG); + }); - it('should handle open-ended edges', function () { - flowParser.parser.parse('graph TD;A---B;') - flowParser.parser.yy.getVertices() - const edges = flowParser.parser.yy.getEdges() + it('should handle open-ended edges', function() { + flowParser.parser.parse('graph TD;A---B;'); + flowParser.parser.yy.getVertices(); + const edges = flowParser.parser.yy.getEdges(); const mockG = { - setEdge: function (start, end, options) { - expect(start).toBe('A') - expect(end).toBe('B') - expect(options.arrowhead).toBe('none') + setEdge: function(start, end, options) { + expect(start).toBe('A'); + expect(end).toBe('B'); + expect(options.arrowhead).toBe('none'); } - } + }; - flowRenderer.addEdges(edges, mockG) - }) + flowRenderer.addEdges(edges, mockG); + }); - it('should handle edges with styles defined', function () { - flowParser.parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;') - flowParser.parser.yy.getVertices() - const edges = flowParser.parser.yy.getEdges() + it('should handle edges with styles defined', function() { + flowParser.parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;'); + flowParser.parser.yy.getVertices(); + const edges = flowParser.parser.yy.getEdges(); const mockG = { - setEdge: function (start, end, options) { - expect(start).toBe('A') - expect(end).toBe('B') - expect(options.arrowhead).toBe('none') - expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;') + setEdge: function(start, end, options) { + expect(start).toBe('A'); + expect(end).toBe('B'); + expect(options.arrowhead).toBe('none'); + expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;'); } - } + }; - flowRenderer.addEdges(edges, mockG) - }) - it('should handle edges with interpolation defined', function () { - flowParser.parser.parse('graph TD;A---B; linkStyle 0 interpolate basis') - flowParser.parser.yy.getVertices() - const edges = flowParser.parser.yy.getEdges() + flowRenderer.addEdges(edges, mockG); + }); + it('should handle edges with interpolation defined', function() { + flowParser.parser.parse('graph TD;A---B; linkStyle 0 interpolate basis'); + flowParser.parser.yy.getVertices(); + const edges = flowParser.parser.yy.getEdges(); const mockG = { - setEdge: function (start, end, options) { - expect(start).toBe('A') - expect(end).toBe('B') - expect(options.arrowhead).toBe('none') - expect(options.curve).toBe('basis') // mocked as string + setEdge: function(start, end, options) { + expect(start).toBe('A'); + expect(end).toBe('B'); + expect(options.arrowhead).toBe('none'); + expect(options.curve).toBe('basis'); // mocked as string } - } + }; - flowRenderer.addEdges(edges, mockG) - }) - it('should handle edges with text and styles defined', function () { - flowParser.parser.parse('graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;') - flowParser.parser.yy.getVertices() - const edges = flowParser.parser.yy.getEdges() + flowRenderer.addEdges(edges, mockG); + }); + it('should handle edges with text and styles defined', function() { + flowParser.parser.parse( + 'graph TD;A---|the text|B; linkStyle 0 stroke:val1,stroke-width:val2;' + ); + flowParser.parser.yy.getVertices(); + const edges = flowParser.parser.yy.getEdges(); const mockG = { - setEdge: function (start, end, options) { - expect(start).toBe('A') - expect(end).toBe('B') - expect(options.arrowhead).toBe('none') - expect(options.label.match('the text')).toBeTruthy() - expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;') + setEdge: function(start, end, options) { + expect(start).toBe('A'); + expect(end).toBe('B'); + expect(options.arrowhead).toBe('none'); + expect(options.label.match('the text')).toBeTruthy(); + expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;'); } - } + }; - flowRenderer.addEdges(edges, mockG) - }) + flowRenderer.addEdges(edges, mockG); + }); - it('should set fill to "none" by default when handling edges', function () { - flowParser.parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;') - flowParser.parser.yy.getVertices() - const edges = flowParser.parser.yy.getEdges() + it('should set fill to "none" by default when handling edges', function() { + flowParser.parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2;'); + flowParser.parser.yy.getVertices(); + const edges = flowParser.parser.yy.getEdges(); const mockG = { - setEdge: function (start, end, options) { - expect(start).toBe('A') - expect(end).toBe('B') - expect(options.arrowhead).toBe('none') - expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;') + setEdge: function(start, end, options) { + expect(start).toBe('A'); + expect(end).toBe('B'); + expect(options.arrowhead).toBe('none'); + expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:none;'); } - } + }; - flowRenderer.addEdges(edges, mockG) - }) + flowRenderer.addEdges(edges, mockG); + }); - it('should not set fill to none if fill is set in linkStyle', function () { - flowParser.parser.parse('graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;') - flowParser.parser.yy.getVertices() - const edges = flowParser.parser.yy.getEdges() + it('should not set fill to none if fill is set in linkStyle', function() { + flowParser.parser.parse( + 'graph TD;A---B; linkStyle 0 stroke:val1,stroke-width:val2,fill:blue;' + ); + flowParser.parser.yy.getVertices(); + const edges = flowParser.parser.yy.getEdges(); const mockG = { - setEdge: function (start, end, options) { - expect(start).toBe('A') - expect(end).toBe('B') - expect(options.arrowhead).toBe('none') - expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:blue;') + setEdge: function(start, end, options) { + expect(start).toBe('A'); + expect(end).toBe('B'); + expect(options.arrowhead).toBe('none'); + expect(options.style).toBe('stroke:val1;stroke-width:val2;fill:blue;'); } - } + }; - flowRenderer.addEdges(edges, mockG) - }) - }) + flowRenderer.addEdges(edges, mockG); + }); + }); - describe('checking validity of input ', function () { - it('it should throw for an invalid definiton', function () { - expect(() => mermaid.parse('this is not a mermaid diagram definition')).toThrow() - }) + describe('checking validity of input ', function() { + it('it should throw for an invalid definiton', function() { + expect(() => mermaid.parse('this is not a mermaid diagram definition')).toThrow(); + }); - it('it should not throw for a valid flow definition', function () { - expect(() => mermaid.parse('graph TD;A--x|text including URL space|B;')).not.toThrow() - }) - it('it should throw for an invalid flow definition', function () { - expect(() => mermaid.parse('graph TQ;A--x|text including URL space|B;')).toThrow() - }) + it('it should not throw for a valid flow definition', function() { + expect(() => mermaid.parse('graph TD;A--x|text including URL space|B;')).not.toThrow(); + }); + it('it should throw for an invalid flow definition', function() { + expect(() => mermaid.parse('graph TQ;A--x|text including URL space|B;')).toThrow(); + }); - it('it should not throw for a valid sequenceDiagram definition', function () { - const text = 'sequenceDiagram\n' + + it('it should not throw for a valid sequenceDiagram definition', function() { + const text = + 'sequenceDiagram\n' + 'Alice->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + @@ -197,12 +202,13 @@ describe('when using mermaid and ', function () { 'Bob-->Alice: I am good thanks!\n' + 'else isSick\n' + 'Bob-->Alice: Feel sick...\n' + - 'end' - expect(() => mermaid.parse(text)).not.toThrow() - }) + 'end'; + expect(() => mermaid.parse(text)).not.toThrow(); + }); - it('it should throw for an invalid sequenceDiagram definition', function () { - const text = 'sequenceDiagram\n' + + it('it should throw for an invalid sequenceDiagram definition', function() { + const text = + 'sequenceDiagram\n' + 'Alice:->Bob: Hello Bob, how are you?\n\n' + '%% Comment\n' + 'Note right of Bob: Bob thinks\n' + @@ -210,8 +216,8 @@ describe('when using mermaid and ', function () { 'Bob-->Alice: I am good thanks!\n' + 'else isSick\n' + 'Bob-->Alice: Feel sick...\n' + - 'end' - expect(() => mermaid.parse(text)).toThrow() - }) - }) -}) + 'end'; + expect(() => mermaid.parse(text)).toThrow(); + }); + }); +}); diff --git a/src/mermaidAPI.js b/src/mermaidAPI.js index 522bdafbd..855d16b7f 100644 --- a/src/mermaidAPI.js +++ b/src/mermaidAPI.js @@ -9,38 +9,38 @@ * In addition to the render function, a number of behavioral configuration options are available. * * @name mermaidAPI -*/ -import * as d3 from 'd3' -import scope from 'scope-css' -import pkg from '../package.json' -import { setConfig, getConfig } from './config' -import { logger, setLogLevel } from './logger' -import utils from './utils' -import flowRenderer from './diagrams/flowchart/flowRenderer' -import flowParser from './diagrams/flowchart/parser/flow' -import flowDb from './diagrams/flowchart/flowDb' -import sequenceRenderer from './diagrams/sequence/sequenceRenderer' -import sequenceParser from './diagrams/sequence/parser/sequenceDiagram' -import sequenceDb from './diagrams/sequence/sequenceDb' -import ganttRenderer from './diagrams/gantt/ganttRenderer' -import ganttParser from './diagrams/gantt/parser/gantt' -import ganttDb from './diagrams/gantt/ganttDb' -import classRenderer from './diagrams/class/classRenderer' -import classParser from './diagrams/class/parser/classDiagram' -import classDb from './diagrams/class/classDb' -import gitGraphRenderer from './diagrams/git/gitGraphRenderer' -import gitGraphParser from './diagrams/git/parser/gitGraph' -import gitGraphAst from './diagrams/git/gitGraphAst' -import infoRenderer from './diagrams/info/infoRenderer' -import infoParser from './diagrams/info/parser/info' -import infoDb from './diagrams/info/infoDb' -import pieRenderer from './diagrams/pie/pieRenderer' -import pieParser from './diagrams/pie/parser/pie' -import pieDb from './diagrams/pie/pieDb' + */ +import * as d3 from 'd3'; +import scope from 'scope-css'; +import pkg from '../package.json'; +import { setConfig, getConfig } from './config'; +import { logger, setLogLevel } from './logger'; +import utils from './utils'; +import flowRenderer from './diagrams/flowchart/flowRenderer'; +import flowParser from './diagrams/flowchart/parser/flow'; +import flowDb from './diagrams/flowchart/flowDb'; +import sequenceRenderer from './diagrams/sequence/sequenceRenderer'; +import sequenceParser from './diagrams/sequence/parser/sequenceDiagram'; +import sequenceDb from './diagrams/sequence/sequenceDb'; +import ganttRenderer from './diagrams/gantt/ganttRenderer'; +import ganttParser from './diagrams/gantt/parser/gantt'; +import ganttDb from './diagrams/gantt/ganttDb'; +import classRenderer from './diagrams/class/classRenderer'; +import classParser from './diagrams/class/parser/classDiagram'; +import classDb from './diagrams/class/classDb'; +import gitGraphRenderer from './diagrams/git/gitGraphRenderer'; +import gitGraphParser from './diagrams/git/parser/gitGraph'; +import gitGraphAst from './diagrams/git/gitGraphAst'; +import infoRenderer from './diagrams/info/infoRenderer'; +import infoParser from './diagrams/info/parser/info'; +import infoDb from './diagrams/info/infoDb'; +import pieRenderer from './diagrams/pie/pieRenderer'; +import pieParser from './diagrams/pie/parser/pie'; +import pieDb from './diagrams/pie/pieDb'; -const themes = {} +const themes = {}; for (const themeName of ['default', 'forest', 'dark', 'neutral']) { - themes[themeName] = require(`./themes/${themeName}/index.scss`) + themes[themeName] = require(`./themes/${themeName}/index.scss`); } /** @@ -75,22 +75,21 @@ for (const themeName of ['default', 'forest', 'dark', 'neutral']) { * @name Configuration */ const config = { - /** theme , the CSS style sheet - * - * **theme** - Choose one of the built-in themes: - * * default - * * forest - * * dark - * * neutral. - * To disable any pre-defined mermaid theme, use "null". - * - * **themeCSS** - Use your own CSS. This overrides **theme**. - *
-  *  "theme": "forest",
-  *  "themeCSS": ".node rect { fill: red; }"
-  * 
- */ + * + * **theme** - Choose one of the built-in themes: + * * default + * * forest + * * dark + * * neutral. + * To disable any pre-defined mermaid theme, use "null". + * + * **themeCSS** - Use your own CSS. This overrides **theme**. + *
+   *  "theme": "forest",
+   *  "themeCSS": ".node rect { fill: red; }"
+   * 
+ */ theme: 'default', themeCSS: undefined, @@ -149,7 +148,6 @@ const config = { * The object containing configurations specific for sequence diagrams */ sequence: { - /** * margin to the right and left of the sequence diagram. * **Default value 50**. @@ -234,7 +232,6 @@ const config = { * **Default value false**. */ showSequenceNumbers: false - }, /** @@ -303,100 +300,100 @@ const config = { }, class: {}, git: {} -} +}; -setLogLevel(config.logLevel) -setConfig(config) +setLogLevel(config.logLevel); +setConfig(config); -function parse (text) { - const graphType = utils.detectType(text) - let parser +function parse(text) { + const graphType = utils.detectType(text); + let parser; - logger.debug('Type ' + graphType) + logger.debug('Type ' + graphType); switch (graphType) { case 'git': - parser = gitGraphParser - parser.parser.yy = gitGraphAst - break + parser = gitGraphParser; + parser.parser.yy = gitGraphAst; + break; case 'flowchart': - parser = flowParser - parser.parser.yy = flowDb - break + parser = flowParser; + parser.parser.yy = flowDb; + break; case 'sequence': - parser = sequenceParser - parser.parser.yy = sequenceDb - break + parser = sequenceParser; + parser.parser.yy = sequenceDb; + break; case 'gantt': - parser = ganttParser - parser.parser.yy = ganttDb - break + parser = ganttParser; + parser.parser.yy = ganttDb; + break; case 'class': - parser = classParser - parser.parser.yy = classDb - break + parser = classParser; + parser.parser.yy = classDb; + break; case 'info': - logger.debug('info info info') - console.warn('In API', pkg.version) + logger.debug('info info info'); + console.warn('In API', pkg.version); - parser = infoParser - parser.parser.yy = infoDb - break + parser = infoParser; + parser.parser.yy = infoDb; + break; case 'pie': - logger.debug('pie') - parser = pieParser - parser.parser.yy = pieDb - break + logger.debug('pie'); + parser = pieParser; + parser.parser.yy = pieDb; + break; } parser.parser.yy.parseError = (str, hash) => { - const error = { str, hash } - throw error - } + const error = { str, hash }; + throw error; + }; - parser.parse(text) + parser.parse(text); } -export const encodeEntities = function (text) { - let txt = text +export const encodeEntities = function(text) { + let txt = text; - txt = txt.replace(/style.*:\S*#.*;/g, function (s) { - const innerTxt = s.substring(0, s.length - 1) - return innerTxt - }) - txt = txt.replace(/classDef.*:\S*#.*;/g, function (s) { - const innerTxt = s.substring(0, s.length - 1) - return innerTxt - }) + txt = txt.replace(/style.*:\S*#.*;/g, function(s) { + const innerTxt = s.substring(0, s.length - 1); + return innerTxt; + }); + txt = txt.replace(/classDef.*:\S*#.*;/g, function(s) { + const innerTxt = s.substring(0, s.length - 1); + return innerTxt; + }); - txt = txt.replace(/#\w+;/g, function (s) { - const innerTxt = s.substring(1, s.length - 1) + txt = txt.replace(/#\w+;/g, function(s) { + const innerTxt = s.substring(1, s.length - 1); - const isInt = /^\+?\d+$/.test(innerTxt) + const isInt = /^\+?\d+$/.test(innerTxt); if (isInt) { - return 'fl°°' + innerTxt + '¶ß' + return 'fl°°' + innerTxt + '¶ß'; } else { - return 'fl°' + innerTxt + '¶ß' + return 'fl°' + innerTxt + '¶ß'; } - }) + }); - return txt -} + return txt; +}; -export const decodeEntities = function (text) { - let txt = text +export const decodeEntities = function(text) { + let txt = text; - txt = txt.replace(/fl°°/g, function () { - return '&#' - }) - txt = txt.replace(/fl°/g, function () { - return '&' - }) - txt = txt.replace(/¶ß/g, function () { - return ';' - }) + txt = txt.replace(/fl°°/g, function() { + return '&#'; + }); + txt = txt.replace(/fl°/g, function() { + return '&'; + }); + txt = txt.replace(/¶ß/g, function() { + return ';'; + }); - return txt -} + return txt; +}; /** * Function that renders an svg with a graph from a chart definition. Usage example below. * @@ -419,183 +416,209 @@ export const decodeEntities = function (text) { * provided a hidden div will be inserted in the body of the page instead. The element will be removed when rendering is * completed. */ -const render = function (id, txt, cb, container) { +const render = function(id, txt, cb, container) { if (typeof container !== 'undefined') { - container.innerHTML = '' + container.innerHTML = ''; - d3.select(container).append('div') + d3.select(container) + .append('div') .attr('id', 'd' + id) .append('svg') .attr('id', id) .attr('width', '100%') .attr('xmlns', 'http://www.w3.org/2000/svg') - .append('g') + .append('g'); } else { - const element = document.querySelector('#' + 'd' + id) + const element = document.querySelector('#' + 'd' + id); if (element) { - element.innerHTML = '' + element.innerHTML = ''; } - d3.select('body').append('div') + d3.select('body') + .append('div') .attr('id', 'd' + id) .append('svg') .attr('id', id) .attr('width', '100%') .attr('xmlns', 'http://www.w3.org/2000/svg') - .append('g') + .append('g'); } - window.txt = txt - txt = encodeEntities(txt) + window.txt = txt; + txt = encodeEntities(txt); - const element = d3.select('#d' + id).node() - const graphType = utils.detectType(txt) + const element = d3.select('#d' + id).node(); + const graphType = utils.detectType(txt); // insert inline style into svg - const svg = element.firstChild - const firstChild = svg.firstChild + const svg = element.firstChild; + const firstChild = svg.firstChild; // pre-defined theme - let style = themes[config.theme] + let style = themes[config.theme]; if (style === undefined) { - style = '' + style = ''; } // user provided theme CSS if (config.themeCSS !== undefined) { - style += `\n${config.themeCSS}` + style += `\n${config.themeCSS}`; } // classDef if (graphType === 'flowchart') { - const classes = flowRenderer.getClasses(txt) + const classes = flowRenderer.getClasses(txt); for (const className in classes) { - style += `\n.${className} > * { ${classes[className].styles.join(' !important; ')} !important; }` + style += `\n.${className} > * { ${classes[className].styles.join( + ' !important; ' + )} !important; }`; } } - const style1 = document.createElement('style') - style1.innerHTML = scope(style, `#${id}`) - svg.insertBefore(style1, firstChild) + const style1 = document.createElement('style'); + style1.innerHTML = scope(style, `#${id}`); + svg.insertBefore(style1, firstChild); - const style2 = document.createElement('style') - const cs = window.getComputedStyle(svg) + const style2 = document.createElement('style'); + const cs = window.getComputedStyle(svg); style2.innerHTML = `#${id} { color: ${cs.color}; font: ${cs.font}; - }` - svg.insertBefore(style2, firstChild) + }`; + svg.insertBefore(style2, firstChild); switch (graphType) { case 'git': - config.flowchart.arrowMarkerAbsolute = config.arrowMarkerAbsolute - gitGraphRenderer.setConf(config.git) - gitGraphRenderer.draw(txt, id, false) - break + config.flowchart.arrowMarkerAbsolute = config.arrowMarkerAbsolute; + gitGraphRenderer.setConf(config.git); + gitGraphRenderer.draw(txt, id, false); + break; case 'flowchart': - config.flowchart.arrowMarkerAbsolute = config.arrowMarkerAbsolute - flowRenderer.setConf(config.flowchart) - flowRenderer.draw(txt, id, false) - break + config.flowchart.arrowMarkerAbsolute = config.arrowMarkerAbsolute; + flowRenderer.setConf(config.flowchart); + flowRenderer.draw(txt, id, false); + break; case 'sequence': - config.sequence.arrowMarkerAbsolute = config.arrowMarkerAbsolute - if (config.sequenceDiagram) { // backwards compatibility - sequenceRenderer.setConf(Object.assign(config.sequence, config.sequenceDiagram)) - console.error('`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.') + config.sequence.arrowMarkerAbsolute = config.arrowMarkerAbsolute; + if (config.sequenceDiagram) { + // backwards compatibility + sequenceRenderer.setConf(Object.assign(config.sequence, config.sequenceDiagram)); + console.error( + '`mermaid config.sequenceDiagram` has been renamed to `config.sequence`. Please update your mermaid config.' + ); } else { - sequenceRenderer.setConf(config.sequence) + sequenceRenderer.setConf(config.sequence); } - sequenceRenderer.draw(txt, id) - break + sequenceRenderer.draw(txt, id); + break; case 'gantt': - config.gantt.arrowMarkerAbsolute = config.arrowMarkerAbsolute - ganttRenderer.setConf(config.gantt) - ganttRenderer.draw(txt, id) - break + config.gantt.arrowMarkerAbsolute = config.arrowMarkerAbsolute; + ganttRenderer.setConf(config.gantt); + ganttRenderer.draw(txt, id); + break; case 'class': - config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute - classRenderer.setConf(config.class) - classRenderer.draw(txt, id) - break + config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute; + classRenderer.setConf(config.class); + classRenderer.draw(txt, id); + break; case 'info': - config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute - infoRenderer.setConf(config.class) - infoRenderer.draw(txt, id, pkg.version) - break + config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute; + infoRenderer.setConf(config.class); + infoRenderer.draw(txt, id, pkg.version); + break; case 'pie': - config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute - pieRenderer.setConf(config.class) - pieRenderer.draw(txt, id, pkg.version) - break + config.class.arrowMarkerAbsolute = config.arrowMarkerAbsolute; + pieRenderer.setConf(config.class); + pieRenderer.draw(txt, id, pkg.version); + break; } - d3.select(`[id="${id}"]`).selectAll('foreignobject > *').attr('xmlns', 'http://www.w3.org/1999/xhtml') + d3.select(`[id="${id}"]`) + .selectAll('foreignobject > *') + .attr('xmlns', 'http://www.w3.org/1999/xhtml'); - let url = '' + let url = ''; if (config.arrowMarkerAbsolute) { - url = window.location.protocol + '//' + window.location.host + window.location.pathname + window.location.search - url = url.replace(/\(/g, '\\(') - url = url.replace(/\)/g, '\\)') + url = + window.location.protocol + + '//' + + window.location.host + + window.location.pathname + + window.location.search; + url = url.replace(/\(/g, '\\('); + url = url.replace(/\)/g, '\\)'); } // Fix for when the base tag is used - let svgCode = d3.select('#d' + id).node().innerHTML.replace(/url\(#arrowhead/g, 'url(' + url + '#arrowhead', 'g') + let svgCode = d3 + .select('#d' + id) + .node() + .innerHTML.replace(/url\(#arrowhead/g, 'url(' + url + '#arrowhead', 'g'); - svgCode = decodeEntities(svgCode) + svgCode = decodeEntities(svgCode); if (typeof cb !== 'undefined') { switch (graphType) { case 'flowchart': - cb(svgCode, flowDb.bindFunctions) - break + cb(svgCode, flowDb.bindFunctions); + break; case 'gantt': - cb(svgCode, ganttDb.bindFunctions) - break + cb(svgCode, ganttDb.bindFunctions); + break; default: - cb(svgCode) + cb(svgCode); } } else { - logger.debug('CB = undefined!') + logger.debug('CB = undefined!'); } - const node = d3.select('#d' + id).node() + const node = d3.select('#d' + id).node(); if (node !== null && typeof node.remove === 'function') { - d3.select('#d' + id).node().remove() + d3.select('#d' + id) + .node() + .remove(); } - return svgCode -} + return svgCode; +}; -const setConf = function (cnf) { +const setConf = function(cnf) { // Top level initially mermaid, gflow, sequenceDiagram and gantt - const lvl1Keys = Object.keys(cnf) + const lvl1Keys = Object.keys(cnf); for (let i = 0; i < lvl1Keys.length; i++) { if (typeof cnf[lvl1Keys[i]] === 'object' && cnf[lvl1Keys[i]] != null) { - const lvl2Keys = Object.keys(cnf[lvl1Keys[i]]) + const lvl2Keys = Object.keys(cnf[lvl1Keys[i]]); for (let j = 0; j < lvl2Keys.length; j++) { - logger.debug('Setting conf ', lvl1Keys[i], '-', lvl2Keys[j]) + logger.debug('Setting conf ', lvl1Keys[i], '-', lvl2Keys[j]); if (typeof config[lvl1Keys[i]] === 'undefined') { - config[lvl1Keys[i]] = {} + config[lvl1Keys[i]] = {}; } - logger.debug('Setting config: ' + lvl1Keys[i] + ' ' + lvl2Keys[j] + ' to ' + cnf[lvl1Keys[i]][lvl2Keys[j]]) - config[lvl1Keys[i]][lvl2Keys[j]] = cnf[lvl1Keys[i]][lvl2Keys[j]] + logger.debug( + 'Setting config: ' + + lvl1Keys[i] + + ' ' + + lvl2Keys[j] + + ' to ' + + cnf[lvl1Keys[i]][lvl2Keys[j]] + ); + config[lvl1Keys[i]][lvl2Keys[j]] = cnf[lvl1Keys[i]][lvl2Keys[j]]; } } else { - config[lvl1Keys[i]] = cnf[lvl1Keys[i]] + config[lvl1Keys[i]] = cnf[lvl1Keys[i]]; } } -} +}; -function initialize (options) { - logger.debug('Initializing mermaidAPI ', pkg.version) +function initialize(options) { + logger.debug('Initializing mermaidAPI ', pkg.version); // Update default config with options supplied at initialization if (typeof options === 'object') { - setConf(options) + setConf(options); } - setConfig(config) - setLogLevel(config.logLevel) + setConfig(config); + setLogLevel(config.logLevel); } // function getConfig () { @@ -608,9 +631,9 @@ const mermaidAPI = { parse, initialize, getConfig -} +}; -export default mermaidAPI +export default mermaidAPI; /** * ## mermaidAPI configuration defaults *
diff --git a/src/mermaidAPI.spec.js b/src/mermaidAPI.spec.js
index 51749677c..a5114356f 100644
--- a/src/mermaidAPI.spec.js
+++ b/src/mermaidAPI.spec.js
@@ -1,45 +1,45 @@
 /* eslint-env jasmine */
-import mermaidAPI from './mermaidAPI'
+import mermaidAPI from './mermaidAPI';
 
-describe('when using mermaidAPI and ', function () {
-  describe('doing initialize ', function () {
-    beforeEach(function () {
-      document.body.innerHTML = ''
-    })
+describe('when using mermaidAPI and ', function() {
+  describe('doing initialize ', function() {
+    beforeEach(function() {
+      document.body.innerHTML = '';
+    });
 
-    it('should copy a literal into the configuration', function () {
-      const orgConfig = mermaidAPI.getConfig()
-      expect(orgConfig.testLiteral).toBe(undefined)
+    it('should copy a literal into the configuration', function() {
+      const orgConfig = mermaidAPI.getConfig();
+      expect(orgConfig.testLiteral).toBe(undefined);
 
-      mermaidAPI.initialize({ 'testLiteral': true })
-      const config = mermaidAPI.getConfig()
+      mermaidAPI.initialize({ testLiteral: true });
+      const config = mermaidAPI.getConfig();
 
-      expect(config.testLiteral).toBe(true)
-    })
-    it('should copy a an object into the configuration', function () {
-      const orgConfig = mermaidAPI.getConfig()
-      expect(orgConfig.testObject).toBe(undefined)
+      expect(config.testLiteral).toBe(true);
+    });
+    it('should copy a an object into the configuration', function() {
+      const orgConfig = mermaidAPI.getConfig();
+      expect(orgConfig.testObject).toBe(undefined);
 
       const object = {
         test1: 1,
         test2: false
-      }
+      };
 
-      mermaidAPI.initialize({ 'testObject': object })
-      mermaidAPI.initialize({ 'testObject': { 'test3': true } })
-      const config = mermaidAPI.getConfig()
+      mermaidAPI.initialize({ testObject: object });
+      mermaidAPI.initialize({ testObject: { test3: true } });
+      const config = mermaidAPI.getConfig();
 
-      expect(config.testObject.test1).toBe(1)
-      expect(config.testObject.test2).toBe(false)
-      expect(config.testObject.test3).toBe(true)
-    })
-  })
-  describe('checking validity of input ', function () {
-    it('it should throw for an invalid definiton', function () {
-      expect(() => mermaidAPI.parse('this is not a mermaid diagram definition')).toThrow()
-    })
-    it('it should not throw for a valid definiton', function () {
-      expect(() => mermaidAPI.parse('graph TD;A--x|text including URL space|B;')).not.toThrow()
-    })
-  })
-})
+      expect(config.testObject.test1).toBe(1);
+      expect(config.testObject.test2).toBe(false);
+      expect(config.testObject.test3).toBe(true);
+    });
+  });
+  describe('checking validity of input ', function() {
+    it('it should throw for an invalid definiton', function() {
+      expect(() => mermaidAPI.parse('this is not a mermaid diagram definition')).toThrow();
+    });
+    it('it should not throw for a valid definiton', function() {
+      expect(() => mermaidAPI.parse('graph TD;A--x|text including URL space|B;')).not.toThrow();
+    });
+  });
+});