From 2b30b0135aecb3c89697e489af7124e5a124eb07 Mon Sep 17 00:00:00 2001 From: Nico Rehwaldt Date: Mon, 14 Aug 2023 12:27:35 +0200 Subject: [PATCH] feat: turn into custom editor Closes https://github.com/bpmn-io/vs-code-bpmn-io/issues/67 --- .gitignore | 2 + media/reset.css | 30 ++ media/vscode.css | 85 ++++ package-lock.json | 552 +++++++++++++++++++- package.json | 154 +++--- rollup.config.js | 34 ++ src/assets/modeler.css | 70 --- src/bpmn-editor.ts | 566 +++++++++++++++++++++ src/client/bpmn-editor.css | 15 + src/client/bpmn-editor.js | 95 ++++ src/dispose.ts | 37 ++ src/extension.ts | 260 +--------- src/features/editing/bpmnModelerBuilder.ts | 161 ------ src/features/editing/editingProvider.ts | 71 --- src/features/editing/index.ts | 1 - src/util.ts | 8 + 16 files changed, 1502 insertions(+), 639 deletions(-) create mode 100644 media/reset.css create mode 100644 media/vscode.css create mode 100644 rollup.config.js delete mode 100644 src/assets/modeler.css create mode 100644 src/bpmn-editor.ts create mode 100644 src/client/bpmn-editor.css create mode 100644 src/client/bpmn-editor.js create mode 100644 src/dispose.ts delete mode 100644 src/features/editing/bpmnModelerBuilder.ts delete mode 100644 src/features/editing/editingProvider.ts delete mode 100644 src/features/editing/index.ts create mode 100644 src/util.ts diff --git a/.gitignore b/.gitignore index ec36452..b5fc1cb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ node_modules *.vsix .DS_Store + +media/bpmn-editor.* diff --git a/media/reset.css b/media/reset.css new file mode 100644 index 0000000..92d0291 --- /dev/null +++ b/media/reset.css @@ -0,0 +1,30 @@ +html { + box-sizing: border-box; + font-size: 13px; +} + +*, +*:before, +*:after { + box-sizing: inherit; +} + +body, +h1, +h2, +h3, +h4, +h5, +h6, +p, +ol, +ul { + margin: 0; + padding: 0; + font-weight: normal; +} + +img { + max-width: 100%; + height: auto; +} diff --git a/media/vscode.css b/media/vscode.css new file mode 100644 index 0000000..8a1d8c1 --- /dev/null +++ b/media/vscode.css @@ -0,0 +1,85 @@ +:root { + --container-paddding: 20px; + --input-padding-vertical: 6px; + --input-padding-horizontal: 4px; + --input-margin-vertical: 4px; + --input-margin-horizontal: 0; +} + +body { + padding: 0; + color: var(--vscode-foreground); + font-size: var(--vscode-font-size); + font-weight: var(--vscode-font-weight); + font-family: var(--vscode-font-family); + background-color: var(--vscode-editor-background); +} + +ol, +ul { + padding-left: var(--container-paddding); +} + +*:focus { + outline-color: var(--vscode-focusBorder) !important; +} + +a { + color: var(--vscode-textLink-foreground); +} + +a:hover, +a:active { + color: var(--vscode-textLink-activeForeground); +} + +code { + font-size: var(--vscode-editor-font-size); + font-family: var(--vscode-editor-font-family); +} + +button { + border: none; + padding: var(--input-padding-vertical) var(--input-padding-horizontal); + width: 100%; + text-align: center; + outline: 1px solid transparent; + outline-offset: 2px !important; + color: var(--vscode-button-foreground); + background: var(--vscode-button-background); +} + +button:hover { + cursor: pointer; + background: var(--vscode-button-hoverBackground); +} + +button:focus { + outline-color: var(--vscode-focusBorder); +} + +button.secondary { + color: var(--vscode-button-secondaryForeground); + background: var(--vscode-button-secondaryBackground); +} + +button.secondary:hover { + background: var(--vscode-button-secondaryHoverBackground); +} + +input:not([type='checkbox']), +textarea { + display: block; + width: 100%; + border: none; + font-family: var(--vscode-font-family); + padding: var(--input-padding-vertical) var(--input-padding-horizontal); + color: var(--vscode-input-foreground); + outline-color: var(--vscode-input-border); + background-color: var(--vscode-input-background); +} + +input::placeholder, +textarea::placeholder { + color: var(--vscode-input-placeholderForeground); +} diff --git a/package-lock.json b/package-lock.json index 9768fa0..5dae6ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,9 @@ "ids": "^1.0.3" }, "devDependencies": { + "@rollup/plugin-commonjs": "^25.0.3", + "@rollup/plugin-node-resolve": "^15.1.0", + "@rollup/plugin-url": "^8.0.1", "@types/chai": "^4.3.3", "@types/glob": "^8.0.0", "@types/mocha": "^10.0.0", @@ -21,7 +24,7 @@ "@types/shelljs": "^0.8.12", "@types/sinon": "^10.0.13", "@types/sinon-chai": "^3.2.8", - "@types/vscode": "1.38.0", + "@types/vscode": "^1.79.2", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.3", @@ -32,6 +35,8 @@ "mocha": "^10.2.0", "nodemon": "^3.0.1", "npm-run-all": "^4.1.5", + "rollup": "^3.28.0", + "rollup-plugin-css-only": "^4.3.0", "shelljs": "^0.8.5", "shx": "^0.3.4", "sinon": "^15.2.0", @@ -40,7 +45,7 @@ }, "engines": { "node": ">= 16", - "vscode": "^1.38.0" + "vscode": "^1.79.2" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -264,6 +269,12 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -309,6 +320,140 @@ "node": ">=14" } }, + "node_modules/@rollup/plugin-commonjs": { + "version": "25.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.3.tgz", + "integrity": "sha512-uBdtWr/H3BVcgm97MUdq2oJmqBR23ny1hOrWe2PKo9FTbjsGqg32jfasJUKYAI5ouqacjRnj65mBB/S79F+GQA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz", + "integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-url/-/plugin-url-8.0.1.tgz", + "integrity": "sha512-8ajztphXb5e19dk3Iwjtm2eSYJR8jFQubZ8pJ1GG2MBMM7/qUedLnZAN+Vt4jqbcT/m27jfjIBocvrzV0giNRw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "make-dir": "^3.1.0", + "mime": "^3.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@sinonjs/commons": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", @@ -368,6 +513,12 @@ "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", "dev": true }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true + }, "node_modules/@types/glob": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.0.0.tgz", @@ -402,6 +553,12 @@ "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", "dev": true }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, "node_modules/@types/semver": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", @@ -454,9 +611,9 @@ "dev": true }, "node_modules/@types/vscode": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.38.0.tgz", - "integrity": "sha512-aGo8LQ4J1YF0T9ORuCO+bhQ5sGR1MXa7VOyOdEP685se3wyQWYUExcdiDi6rvaK61KUwfzzA19JRLDrUbDl7BQ==", + "version": "1.81.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.81.0.tgz", + "integrity": "sha512-YIaCwpT+O2E7WOMq0eCgBEABE++SX3Yl/O02GoMIF2DO3qAtvw7m6BXFYsxnc6XyzwZgh6/s/UG78LSSombl2w==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -1009,6 +1166,18 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -1157,6 +1326,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, "node_modules/component-event": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/component-event/-/component-event-0.2.1.tgz", @@ -1243,6 +1418,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/define-properties": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", @@ -1944,6 +2128,12 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -2682,6 +2872,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -2695,9 +2900,9 @@ } }, "node_modules/is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -2751,6 +2956,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "node_modules/is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -2805,6 +3016,15 @@ "node": ">=8" } }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -3176,6 +3396,42 @@ "node": ">=10" } }, + "node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -3207,6 +3463,18 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/min-dash": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/min-dash/-/min-dash-4.1.1.tgz", @@ -4080,12 +4348,20 @@ } }, "node_modules/resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", "dev": true, "dependencies": { - "path-parse": "^1.0.6" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/resolve-from": { @@ -4142,6 +4418,37 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rollup": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", + "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-css-only": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.3.0.tgz", + "integrity": "sha512-BsiCqJJQzZh2lQiHY5irejRoJ3I1EUFHEi5PjVqsr+EmOh54YrWVwd3YZEXnQJ2+fzlhif0YM/Kf0GuH90GAdQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "5" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "rollup": "<4" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -5207,6 +5514,12 @@ } } }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -5240,6 +5553,89 @@ "dev": true, "optional": true }, + "@rollup/plugin-commonjs": { + "version": "25.0.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.3.tgz", + "integrity": "sha512-uBdtWr/H3BVcgm97MUdq2oJmqBR23ny1hOrWe2PKo9FTbjsGqg32jfasJUKYAI5ouqacjRnj65mBB/S79F+GQA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.27.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@rollup/plugin-node-resolve": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.1.0.tgz", + "integrity": "sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + } + }, + "@rollup/plugin-url": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-url/-/plugin-url-8.0.1.tgz", + "integrity": "sha512-8ajztphXb5e19dk3Iwjtm2eSYJR8jFQubZ8pJ1GG2MBMM7/qUedLnZAN+Vt4jqbcT/m27jfjIBocvrzV0giNRw==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "make-dir": "^3.1.0", + "mime": "^3.0.0" + } + }, + "@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + } + }, "@sinonjs/commons": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", @@ -5298,6 +5694,12 @@ "integrity": "sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==", "dev": true }, + "@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true + }, "@types/glob": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.0.0.tgz", @@ -5332,6 +5734,12 @@ "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", "dev": true }, + "@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, "@types/semver": { "version": "7.5.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", @@ -5386,9 +5794,9 @@ "dev": true }, "@types/vscode": { - "version": "1.38.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.38.0.tgz", - "integrity": "sha512-aGo8LQ4J1YF0T9ORuCO+bhQ5sGR1MXa7VOyOdEP685se3wyQWYUExcdiDi6rvaK61KUwfzzA19JRLDrUbDl7BQ==", + "version": "1.81.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.81.0.tgz", + "integrity": "sha512-YIaCwpT+O2E7WOMq0eCgBEABE++SX3Yl/O02GoMIF2DO3qAtvw7m6BXFYsxnc6XyzwZgh6/s/UG78LSSombl2w==", "dev": true }, "@typescript-eslint/eslint-plugin": { @@ -5767,6 +6175,12 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -5879,6 +6293,12 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, "component-event": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/component-event/-/component-event-0.2.1.tgz", @@ -5947,6 +6367,12 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, "define-properties": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", @@ -6477,6 +6903,12 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, "esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -7023,6 +7455,15 @@ "has-tostringtag": "^1.0.0" } }, + "is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "requires": { + "builtin-modules": "^3.3.0" + } + }, "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -7030,9 +7471,9 @@ "dev": true }, "is-core-module": { - "version": "2.12.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz", - "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==", + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", "dev": true, "requires": { "has": "^1.0.3" @@ -7068,6 +7509,12 @@ "is-extglob": "^2.1.1" } }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "is-negative-zero": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", @@ -7101,6 +7548,15 @@ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -7382,6 +7838,32 @@ "yallist": "^4.0.0" } }, + "magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.13" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, "memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -7404,6 +7886,12 @@ "picomatch": "^2.3.1" } }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true + }, "min-dash": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/min-dash/-/min-dash-4.1.1.tgz", @@ -8076,12 +8564,14 @@ "dev": true }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", + "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", "dev": true, "requires": { - "path-parse": "^1.0.6" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, "resolve-from": { @@ -8121,6 +8611,24 @@ } } }, + "rollup": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", + "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-css-only": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-4.3.0.tgz", + "integrity": "sha512-BsiCqJJQzZh2lQiHY5irejRoJ3I1EUFHEi5PjVqsr+EmOh54YrWVwd3YZEXnQJ2+fzlhif0YM/Kf0GuH90GAdQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "5" + } + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", diff --git a/package.json b/package.json index 13781a5..93c41e5 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "url": "https://github.com/bpmn-io/vs-code-bpmn-io" }, "engines": { - "vscode": "^1.38.0", + "vscode": "^1.79.2", "node": ">= 16" }, "icon": "resources/logo_marketplace.png", @@ -22,73 +22,106 @@ "bpmn" ], "activationEvents": [ - "onLanguage:bpmn", - "onCommand:extension.bpmn-io.edit", - "onWebviewPanel:bpmn-io.edit" + "onCommand:extension.bpmn-io.edit" ], "main": "./out/extension.js", "contributes": { - "languages": [ - { - "id": "bpmn", - "aliases": [ - "BPMN", - "bpmn" - ], - "extensions": [ - ".bpmn2", - ".bpmn", - ".bpmn20.xml" - ] - } - ], "commands": [ { - "command": "extension.bpmn-io.edit", - "title": "Open BPMN Modeler", - "icon": { - "light": "./resources/icon_light.svg", - "dark": "./resources/icon_dark.svg" - } + "command": "bpmn-io.bpmnEditor.new", + "title": "Create new BPMN Document", + "category": "BPMN" + }, + { + "command": "bpmn-io.bpmnEditor.spaceTool", + "title": "Activate space tool", + "category": "BPMN", + "when": "activeCustomEditorId === 'bpmn-io.bpmnEditor'" + }, + { + "command": "bpmn-io.bpmnEditor.lassoTool", + "title": "Activate lasso tool", + "category": "BPMN", + "when": "activeCustomEditorId === 'bpmn-io.bpmnEditor'" + }, + { + "command": "bpmn-io.bpmnEditor.handTool", + "title": "Activate hand tool", + "category": "BPMN", + "when": "activeCustomEditorId === 'bpmn-io.bpmnEditor'" + }, + { + "command": "bpmn-io.bpmnEditor.globalConnectTool", + "title": "Activate connect tool", + "category": "BPMN", + "when": "activeCustomEditorId === 'bpmn-io.bpmnEditor'" + }, + { + "command": "bpmn-io.bpmnEditor.directEditing", + "title": "Edit name", + "category": "BPMN", + "when": "activeCustomEditorId === 'bpmn-io.bpmnEditor'" + }, + { + "command": "bpmn-io.bpmnEditor.replaceElement", + "title": "Replace element", + "category": "BPMN", + "when": "activeCustomEditorId === 'bpmn-io.bpmnEditor'" + }, + { + "command": "bpmn-io.bpmnEditor.find", + "title": "Find element", + "category": "BPMN", + "when": "activeCustomEditorId === 'bpmn-io.bpmnEditor'" } ], "keybindings": [ { - "command": "extension.bpmn-io.edit", - "key": "shift+ctrl+v", - "mac": "shift+cmd+v", - "when": "editorTextFocus && resourceLangId == bpmn" + "key": "s", + "command": "bpmn-io.bpmnEditor.spaceTool", + "when": "!inputFocus" + }, + { + "key": "c", + "command": "bpmn-io.bpmnEditor.globalConnectTool", + "when": "!inputFocus" + }, + { + "key": "h", + "command": "bpmn-io.bpmnEditor.handTool", + "when": "!inputFocus" + }, + { + "key": "l", + "command": "bpmn-io.bpmnEditor.lassoTool", + "when": "!inputFocus" + }, + { + "key": "e", + "command": "bpmn-io.bpmnEditor.directEditing", + "when": "!inputFocus" + }, + { + "key": "r", + "command": "bpmn-io.bpmnEditor.replaceElement", + "when": "!inputFocus" + }, + { + "key": "ctrl+f", + "command": "bpmn-io.bpmnEditor.find" } ], - "menus": { - "commandPalette": [ - { - "when": "resourceLangId == bpmn", - "command": "extension.bpmn-io.edit" - } - ], - "explorer/context": [ - { - "when": "resourceLangId == bpmn", - "command": "extension.bpmn-io.edit", - "group": "navigation" - } - ], - "editor/context": [ - { - "when": "resourceLangId == bpmn", - "command": "extension.bpmn-io.edit", - "group": "navigation" - } - ], - "editor/title": [ - { - "when": "resourceLangId == bpmn", - "command": "extension.bpmn-io.edit", - "group": "navigation" - } - ] - } + "customEditors": [ + { + "viewType": "bpmn-io.bpmnEditor", + "displayName": "BPMN Editor", + "selector": [ + { + "filenamePattern": "*.bpmn" + } + ] + } + ] }, "scripts": { "all": "run-s lint test", @@ -105,6 +138,9 @@ "test": "node ./out/test/runTest.js" }, "devDependencies": { + "@rollup/plugin-commonjs": "^25.0.3", + "@rollup/plugin-node-resolve": "^15.1.0", + "@rollup/plugin-url": "^8.0.1", "@types/chai": "^4.3.3", "@types/glob": "^8.0.0", "@types/mocha": "^10.0.0", @@ -112,7 +148,7 @@ "@types/shelljs": "^0.8.12", "@types/sinon": "^10.0.13", "@types/sinon-chai": "^3.2.8", - "@types/vscode": "1.38.0", + "@types/vscode": "^1.79.2", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", "@vscode/test-electron": "^2.3.3", @@ -123,6 +159,8 @@ "mocha": "^10.2.0", "nodemon": "^3.0.1", "npm-run-all": "^4.1.5", + "rollup": "^3.28.0", + "rollup-plugin-css-only": "^4.3.0", "shelljs": "^0.8.5", "shx": "^0.3.4", "sinon": "^15.2.0", diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 0000000..f0fa605 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,34 @@ +/* eslint-env node */ + +const resolve = require('@rollup/plugin-node-resolve'); +const commonjs = require('@rollup/plugin-commonjs'); +const url = require('@rollup/plugin-url'); + +const css = require('rollup-plugin-css-only'); + +const distDirectory = './media'; + +module.exports = [ + { + input: 'src/client/bpmn-editor.js', + output: { + sourcemap: true, + format: 'iife', + file: distDirectory + '/bpmn-editor.js' + }, + plugins: [ + url({ + fileName: '[dirname][filename][extname]', + publicPath: '/media/' + }), + + css({ output: 'bpmn-editor.css' }), + + resolve(), + commonjs() + ], + watch: { + clearScreen: false + } + } +]; diff --git a/src/assets/modeler.css b/src/assets/modeler.css deleted file mode 100644 index 6dedb83..0000000 --- a/src/assets/modeler.css +++ /dev/null @@ -1,70 +0,0 @@ -* { - box-sizing: border-box; -} - -body, html { - font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; - - font-size: 12px; - - height: 100%; - padding: 0; - margin: 0; -} - -.content, -.content > #canvas { - width: 100%; - height: 100%; - overflow: hidden; - background-color: white; -} - -.buttons { - position: fixed; - bottom: 0; - left: 15px; - list-style: none; -} - -.buttons .icon { - font-size: 24px !important; - text-align: center !important; - color: #404040; - width: 32px; - height: 32px; -} - -.buttons .icon:hover { - color: #005DF7 -} - -.buttons .icon.hidden { - display: none; -} - -.spinner { - display: inline-block; - height: 24px; - width: 24px; - margin-bottom: 8px; - margin-left: 4px; - border-radius: 50%; - border: 2px solid gray; - border-top-color: transparent; - animation: lai-spinnair 1s linear infinite; - visibility: hidden; -} - -.active { - visibility: visible; -} - -@keyframes lai-spinnair { - 0% { - transform: rotateZ(0); - } - 100% { - transform: rotateZ(360deg); - } -} \ No newline at end of file diff --git a/src/bpmn-editor.ts b/src/bpmn-editor.ts new file mode 100644 index 0000000..e1a63cf --- /dev/null +++ b/src/bpmn-editor.ts @@ -0,0 +1,566 @@ +import * as vscode from 'vscode'; +import { Disposable, disposeAll } from './dispose'; +import { getNonce } from './util'; + +/** + * Define the type of edits used in paw draw files. + */ +interface BpmnEdit { + readonly idx: number; +} + +interface BpmnDocumentDelegate { + getText(): Promise; +} + +/** + * Define the document (the data model) used for paw draw files. + */ +class BpmnDocument extends Disposable implements vscode.CustomDocument { + + static async create( + uri: vscode.Uri, + backupId: string | undefined, + delegate: BpmnDocumentDelegate, + ): Promise> { + + // If we have a backup, read that. Otherwise read the resource from the workspace + const dataFile = typeof backupId === 'string' ? vscode.Uri.parse(backupId) : uri; + const text = await BpmnDocument.readFile(dataFile); + return new BpmnDocument(uri, text, delegate); + } + + private static async readFile(uri: vscode.Uri): Promise { + if (uri.scheme === 'untitled') { + return ''; + } + return Buffer.from(await vscode.workspace.fs.readFile(uri)).toString('utf8'); + } + + private readonly _uri: vscode.Uri; + + private _text: string; + private _edits: Array = []; + + private readonly _delegate: BpmnDocumentDelegate; + + private constructor( + uri: vscode.Uri, + initialText: string, + delegate: BpmnDocumentDelegate + ) { + super(); + this._uri = uri; + this._text = initialText; + this._delegate = delegate; + } + + public get uri() { return this._uri; } + + /** + * Returns the document text + */ + public getText(): string { return this._text; } + + private readonly _onDidDispose = this._register(new vscode.EventEmitter()); + + /** + * Fired when the document is disposed of. + */ + public readonly onDidDispose = this._onDidDispose.event; + + private readonly _onDidChangeDocument = this._register(new vscode.EventEmitter<{ + readonly content?: string; + readonly undo?: boolean; + readonly redo?: boolean; + }>()); + + /** + * Fired to notify webviews that the document has changed. + */ + public readonly onDidChangeContent = this._onDidChangeDocument.event; + + private readonly _onDidChange = this._register(new vscode.EventEmitter<{ + readonly label: string; + undo(): Thenable | void; + redo(): Thenable | void + }>()); + + /** + * Fired to tell VS Code that an edit has occurred in the document. + * + * This updates the document's dirty indicator. + */ + public readonly onDidChange = this._onDidChange.event; + + /** + * Called by VS Code when there are no more references to the document. + * + * This happens when all editors for it have been closed. + */ + dispose(): void { + this._onDidDispose.fire(); + super.dispose(); + } + + /** + * Called when the user edits the document in a webview. + * + * This fires an event to notify VS Code that the document has been edited. + */ + makeEdit(edit: BpmnEdit) { + + // initial import + if (edit.idx === -1) { + return; + } + + const [ + lastEdit = { idx: -1 } + ] = this._edits.slice(-1); + + // un- or re-doing a known edit + if (lastEdit.idx === edit.idx) { + return; + } + + this._edits.push(edit); + + this._onDidChange.fire({ + label: 'edit', + undo: async () => { + this._edits.pop(); + this._onDidChangeDocument.fire({ + undo: true + }); + }, + redo: async () => { + this._edits.push(edit); + this._onDidChangeDocument.fire({ + redo: true + }); + } + }); + } + + /** + * Called by VS Code when the user saves the document. + */ + async save(cancellation: vscode.CancellationToken): Promise { + await this.saveAs(this.uri, cancellation); + } + + /** + * Called by VS Code when the user saves the document to a new location. + */ + async saveAs(targetResource: vscode.Uri, cancellation: vscode.CancellationToken): Promise { + const text = await this._delegate.getText(); + if (cancellation.isCancellationRequested) { + return; + } + + this._text = text; + + await vscode.workspace.fs.writeFile(targetResource, Buffer.from(text, 'utf8')); + } + + /** + * Called by VS Code when the user calls `revert` on a document. + */ + async revert(_cancellation: vscode.CancellationToken): Promise { + const text = await BpmnDocument.readFile(this.uri); + + return this.reset(text); + } + + /** + * Resets document to a particular state + */ + async reset(content: string) { + + this._text = content; + this._edits = []; + + this._onDidChangeDocument.fire({ + content + }); + } + + /** + * Called by VS Code to backup the edited document. + * + * These backups are used to implement hot exit. + */ + async backup(destination: vscode.Uri, cancellation: vscode.CancellationToken): Promise { + await this.saveAs(destination, cancellation); + + return { + id: destination.toString(), + delete: async () => { + try { + await vscode.workspace.fs.delete(destination); + } catch { + + // noop + } + } + }; + } +} + +/** + * Provider for visual BPMN editing. + * + * This provider demonstrates: + * + * - How to implement a custom editor for binary files. + * - Setting up the initial webview for a custom editor. + * - Loading scripts and styles in a custom editor. + * - Communication between VS Code and the custom editor. + * - Using CustomDocuments to store information that is shared between multiple custom editors. + * - Implementing save, undo, redo, and revert. + * - Backing up a custom editor. + */ +export class BpmnEditor implements vscode.CustomEditorProvider { + + private static newFileId = 1; + + public static register(context: vscode.ExtensionContext): vscode.Disposable { + context.subscriptions.push( + vscode.commands.registerCommand('bpmn-io.bpmnEditor.new', () => { + + const currentDocumentUri = + vscode.window.activeTextEditor?.document.uri || + vscode.window.activeNotebookEditor?.notebook.uri; + + const workspaceFolders = vscode.workspace.workspaceFolders; + + const workspaceUri = workspaceFolders && workspaceFolders[0].uri; + const fileName = `new-${BpmnEditor.newFileId++}.bpmn`; + + let uri = vscode.Uri.parse(`untitled://${fileName}`); + + if (currentDocumentUri || workspaceUri) { + uri = vscode.Uri.joinPath((currentDocumentUri || workspaceUri)!, fileName).with({ scheme: 'untitled' }); + } + + vscode.commands.executeCommand('vscode.openWith', uri, BpmnEditor.viewType); + }) + ); + + return vscode.window.registerCustomEditorProvider( + BpmnEditor.viewType, + new BpmnEditor(context), + { + webviewOptions: { + retainContextWhenHidden: true, + }, + supportsMultipleEditorsPerDocument: false + } + ); + } + + private static readonly viewType = 'bpmn-io.bpmnEditor'; + + /** + * Tracks all known webviews + */ + private readonly webviews = new WebviewCollection(); + + private _activeEditor : vscode.WebviewPanel | null = null; + + constructor( + private readonly _context: vscode.ExtensionContext + ) { + + const actions = [ + 'lassoTool', + 'handTool', + 'spaceTool', + 'globalConnectTool', + 'directEditing', + 'find', + 'replaceElement' + ]; + + for (const action of actions) { + this._context.subscriptions.push( + vscode.commands.registerCommand(`bpmn-io.bpmnEditor.${action}`, () => { + + console.log('trigger action', action); + + const activeEditor = this._activeEditor; + + if (!activeEditor) { + console.log('no active editor!'); + return; + } + + this.postMessage(activeEditor, 'triggerAction', { + action + }); + }) + ); + } + } + + // #region CustomEditorProvider + + async openCustomDocument( + uri: vscode.Uri, + openContext: { backupId?: string }, + _token: vscode.CancellationToken + ): Promise { + const document: BpmnDocument = await BpmnDocument.create(uri, openContext.backupId, { + getText: async () => { + const webviewsForDocument = Array.from(this.webviews.get(document.uri)); + if (!webviewsForDocument.length) { + throw new Error('Could not find webview to save for'); + } + const panel = webviewsForDocument[0]; + const response = await this.postMessageWithResponse(panel, 'getText', {}); + return String(response); + } + }); + + const listeners: vscode.Disposable[] = []; + + listeners.push(document.onDidChange(e => { + + // Tell VS Code that the document has been edited by the user. + this._onDidChangeCustomDocument.fire({ + document, + ...e, + }); + })); + + listeners.push(vscode.workspace.onDidChangeTextDocument(e => { + const { + document: textDocument + } = e; + + console.log('TEXT DOCUMENT CHANGED', e); + + if (textDocument.uri.toString() !== document.uri.toString()) { + return; + } + + const newText = textDocument.getText(); + + if (newText !== document.getText()) { + console.log('RESET', document.uri); + + return document.reset(newText); + } + })); + + listeners.push(document.onDidChangeContent(e => { + + // Update all webviews when the document changes + for (const webviewPanel of this.webviews.get(document.uri)) { + this.postMessage(webviewPanel, 'update', { + undo: e.undo, + redo: e.redo, + content: e.content + }); + } + })); + + document.onDidDispose(() => disposeAll(listeners)); + + return document; + } + + async resolveCustomEditor( + document: BpmnDocument, + webviewPanel: vscode.WebviewPanel, + _token: vscode.CancellationToken + ): Promise { + + // add the webview to our internal set of active webviews + this.webviews.add(document.uri, webviewPanel); + + webviewPanel.webview.options = { + enableScripts: true, + }; + webviewPanel.webview.html = this.getHtmlForWebview(webviewPanel.webview); + + webviewPanel.webview.onDidReceiveMessage(e => this.onMessage(document, e)); + + webviewPanel.webview.onDidReceiveMessage(e => { + if (e.type === 'ready') { + if (document.uri.scheme === 'untitled') { + this.postMessage(webviewPanel, 'init', { + untitled: true, + editable: true, + }); + } else { + const editable = vscode.workspace.fs.isWritableFileSystem(document.uri.scheme); + + this.postMessage(webviewPanel, 'init', { + content: document.getText(), + editable, + }); + } + } + }); + + webviewPanel.onDidChangeViewState(e => { + + const { webviewPanel } = e; + + if (webviewPanel.active) { + this._activeEditor = webviewPanel; + } else if (this._activeEditor === webviewPanel) { + this._activeEditor = null; + } + }); + + // set as active + this._activeEditor = webviewPanel; + } + + private readonly _onDidChangeCustomDocument = new vscode.EventEmitter>(); + public readonly onDidChangeCustomDocument = this._onDidChangeCustomDocument.event; + + public saveCustomDocument(document: BpmnDocument, cancellation: vscode.CancellationToken): Thenable { + return document.save(cancellation); + } + + public saveCustomDocumentAs(document: BpmnDocument, destination: vscode.Uri, cancellation: vscode.CancellationToken): Thenable { + return document.saveAs(destination, cancellation); + } + + public revertCustomDocument(document: BpmnDocument, cancellation: vscode.CancellationToken): Thenable { + return document.revert(cancellation); + } + + public backupCustomDocument(document: BpmnDocument, context: vscode.CustomDocumentBackupContext, cancellation: vscode.CancellationToken): Thenable { + return document.backup(context.destination, cancellation); + } + + // #endregion + + /** + * Get the static HTML used for in our editor's webviews. + */ + private getHtmlForWebview(webview: vscode.Webview): string { + + // local path to script and css for the webview + const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath( + this._context.extensionUri, 'media', 'bpmn-editor.js')); + + const styleResetUri = webview.asWebviewUri(vscode.Uri.joinPath( + this._context.extensionUri, 'media', 'reset.css')); + + const styleVSCodeUri = webview.asWebviewUri(vscode.Uri.joinPath( + this._context.extensionUri, 'media', 'vscode.css')); + + const styleMainUri = webview.asWebviewUri(vscode.Uri.joinPath( + this._context.extensionUri, 'media', 'bpmn-editor.css')); + + // use a nonce to whitelist which scripts can be run + const nonce = getNonce(); + + return /* html */` + + + + + + + + + + + + + + + BPMN Editor + + +
+ + + + `; + } + + private _requestId = 1; + private readonly _callbacks = new Map void>(); + + private postMessageWithResponse(panel: vscode.WebviewPanel, type: string, body: any): Promise { + const requestId = this._requestId++; + const p = new Promise(resolve => this._callbacks.set(requestId, resolve)); + panel.webview.postMessage({ type, requestId, body }); + return p; + } + + private postMessage(panel: vscode.WebviewPanel, type: string, body: any = {}): void { + panel.webview.postMessage({ type, body }); + } + + private onMessage(document: BpmnDocument, message: any) { + switch (message.type) { + case 'change': + case 'import': + return document.makeEdit(message as BpmnEdit); + + case 'response': + return ( + this._callbacks.get(message.requestId) + )?.(message.body); + } + } +} + +/** + * Tracks all webviews. + */ +class WebviewCollection { + + private readonly _webviews = new Set<{ + readonly resource: string; + readonly webviewPanel: vscode.WebviewPanel; + }>(); + + /** + * Get all known webviews for a given uri. + */ + public *get(uri: vscode.Uri): Iterable { + const key = uri.toString(); + for (const entry of this._webviews) { + if (entry.resource === key) { + yield entry.webviewPanel; + } + } + } + + /** + * Add a new webview to the collection. + */ + public add(uri: vscode.Uri, webviewPanel: vscode.WebviewPanel) { + const entry = { resource: uri.toString(), webviewPanel }; + this._webviews.add(entry); + + webviewPanel.onDidDispose(() => { + this._webviews.delete(entry); + }); + } + + public find(cb: (e: vscode.WebviewPanel) => boolean) { + for (const entry of this._webviews) { + const { webviewPanel } = entry; + + if (cb(webviewPanel)) { + return webviewPanel; + } + } + + return null; + } +} diff --git a/src/client/bpmn-editor.css b/src/client/bpmn-editor.css new file mode 100644 index 0000000..ca36863 --- /dev/null +++ b/src/client/bpmn-editor.css @@ -0,0 +1,15 @@ +html, body { + width: 100%; + height: 100%; +} + +body { + color: #333; + background: white; +} + +#canvas { + overflow: hidden; + width: 100%; + height: 100%; +} diff --git a/src/client/bpmn-editor.js b/src/client/bpmn-editor.js new file mode 100644 index 0000000..0dc8654 --- /dev/null +++ b/src/client/bpmn-editor.js @@ -0,0 +1,95 @@ +/* eslint-env browser */ + +/* global acquireVsCodeApi */ + +import 'bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css'; +import 'bpmn-js/dist/assets/diagram-js.css'; +import 'bpmn-js/dist/assets/bpmn-js.css'; + +import './bpmn-editor.css'; + +import BpmnModeler from 'bpmn-js/lib/Modeler'; + + +/** + * @type { import('vscode') } + */ +const vscode = acquireVsCodeApi(); + +const modeler = new BpmnModeler({ + container: '#canvas' +}); + +modeler.on('import.done', () => { + return vscode.postMessage({ + type: 'import', + idx: -1 + }); +}); + + +modeler.on('commandStack.changed', () => { + + /** + * @type { import('diagram-js/lib/command/CommandStack').default } + */ + const commandStack = modeler.get('commandStack'); + + return vscode.postMessage({ + type: 'change', + idx: commandStack._stackIdx + }); +}); + +// handle messages from the extension +window.addEventListener('message', async (event) => { + + const { + type, + body, + requestId + } = event.data; + + console.log('message', type, body); + + switch (type) { + case 'init': + if (body.untitled) { + return modeler.createDiagram(); + } else { + return modeler.importXML(body.content); + } + + case 'update': { + if (body.content) { + return modeler.importXML(body.content); + } + + if (body.undo) { + return modeler.get('commandStack').undo(); + } + + if (body.redo) { + return modeler.get('commandStack').redo(); + } + + break; + } + + case 'triggerAction': + return modeler.get('editorActions').trigger(body.action, body.options); + + case 'getText': + return modeler.saveXML({ format: true }).then(({ xml }) => { + return vscode.postMessage({ + type: 'response', + requestId, + body: xml + }); + }); + + } +}); + +// signal to VS Code that the webview is initialized +vscode.postMessage({ type: 'ready' }); diff --git a/src/dispose.ts b/src/dispose.ts new file mode 100644 index 0000000..d82234c --- /dev/null +++ b/src/dispose.ts @@ -0,0 +1,37 @@ +import * as vscode from 'vscode'; + +export function disposeAll(disposables: vscode.Disposable[]): void { + while (disposables.length) { + const item = disposables.pop(); + if (item) { + item.dispose(); + } + } +} + +export abstract class Disposable { + private _isDisposed = false; + + protected _disposables: vscode.Disposable[] = []; + + public dispose(): any { + if (this._isDisposed) { + return; + } + this._isDisposed = true; + disposeAll(this._disposables); + } + + protected _register(value: T): T { + if (this._isDisposed) { + value.dispose(); + } else { + this._disposables.push(value); + } + return value; + } + + protected get isDisposed(): boolean { + return this._isDisposed; + } +} diff --git a/src/extension.ts b/src/extension.ts index 10d0ac6..1e942ae 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,261 +1,9 @@ -'use strict'; - import * as vscode from 'vscode'; -import { ExtensionContext, Uri, WebviewPanel, Webview } from 'vscode'; - -import * as path from 'node:path'; - -import * as fs from 'node:fs'; - -import { EditingProvider } from './features/editing'; - -const editingType = 'bpmn-io.editing'; - -const editCommand = 'extension.bpmn-io.edit'; - -function createPanel( - context: ExtensionContext, - uri: Uri, - provider: EditingProvider -): BpmnEditorPanel { - - const editorColumn = - (vscode.window.activeTextEditor && - vscode.window.activeTextEditor.viewColumn) || - vscode.ViewColumn.One; - - const panel = vscode.window.createWebviewPanel( - editingType, - getPanelTitle(uri, provider), - editorColumn, - getWebviewOptions(context, uri) - ); - - // set content - panel.webview.html = provider.provideTextDocumentContent(uri, panel.webview); - - // set panel icons - const { - extensionPath - } = context; - - panel.iconPath = { - light: getUri(extensionPath, 'resources', 'icon_light.svg'), - dark: getUri(extensionPath, 'resources', 'icon_dark.svg') - }; - - // handling messages from the webview content - panel.webview.onDidReceiveMessage( - message => { - switch (message.command) { - case 'saveContent': - return saveFile(uri, message.content); - } - }, - undefined, - context.subscriptions - ); - - return { panel, resource: uri, provider }; -} - -function saveFile(uri: vscode.Uri, content: string) { - const { fsPath: docPath } = uri.with({ scheme: 'vscode-resource' }); - - fs.writeFileSync(docPath, content, { encoding: 'utf8' }); -} - -function refresh( - editor: BpmnEditorPanel -) { - const { - resource, - panel, - provider - } = editor; - - panel.webview.html = - provider.provideTextDocumentContent(resource, panel.webview); -} - -function autoSaveIfConfigured(editorPanel: BpmnEditorPanel, expectedStates: string[]) { - const config = vscode.workspace.getConfiguration(); - - const autoSaveConfiguration: any = config.get('files.autoSave'); - - // do not save changes if autosave option does not satisfy - if ( - autoSaveConfiguration === 'off' || - expectedStates.indexOf(autoSaveConfiguration) < 0 - ) { - return; - } - - sendMessage('saveFile', editorPanel.panel.webview); -} - - -// Extension API ////////// - -export interface BpmnEditorPanel { - panel: WebviewPanel; - resource: Uri; - provider: EditingProvider; -} - -export function activate(context: ExtensionContext) { - - const openedPanels: BpmnEditorPanel[] = []; - const editingProvider = new EditingProvider(context); - - const _revealIfAlreadyOpened = ( - uri: Uri, - provider: EditingProvider - ): boolean => { - - const opened = openedPanels.find(panel => { - const { - resource, - provider: panelProvider - } = panel; - - return resource.fsPath === uri.fsPath && panelProvider === provider; - }); - - if (!opened) { - return false; - } - - opened.panel.reveal(opened.panel.viewColumn); - - return true; - }; - - const _registerPanel = ( - editorPanel: BpmnEditorPanel - ): void => { - - // on editor closed - editorPanel.panel.onDidDispose(() => { - openedPanels.splice(openedPanels.indexOf(editorPanel), 1); - - /** - * Note @pinussilvestrus - * - * We currently can't retrieve when a webview panel will be closed to save changes - * before, cf. https://github.com/bpmn-io/vs-code-bpmn-io/issues/71#issuecomment-637543431 - */ - // autosaveIfConfigured(editorPanel, ['onFocusChange', 'onWindowChange', 'afterDelay']); - }); - - // on editor visibility changed - editorPanel.panel.onDidChangeViewState(() => { - refresh(editorPanel); - - autoSaveIfConfigured(editorPanel, [ 'onFocusChange', 'onWindowChange' ]); - }); - - openedPanels.push(editorPanel); - }; - - const _registerCommands = (): void => { - - context.subscriptions.push(vscode.commands.registerCommand(editCommand, (uri: Uri) => { - const documentUri = getDocumentUri(uri); - - if (documentUri && !_revealIfAlreadyOpened(documentUri, editingProvider)) { - const panel = createPanel(context, documentUri, editingProvider); - - _registerPanel(panel); - - return panel; - } - })); - }; - - const _serializePanel = ( - provider: EditingProvider - ): void => { - - const viewType = editingType; - - if (vscode.window.registerWebviewPanelSerializer) { - vscode.window.registerWebviewPanelSerializer(viewType, { - async deserializeWebviewPanel(panel: WebviewPanel, state: any) { - - if (!state || !state.resourcePath) { - return; - } - - const resource = Uri.parse(state.resourcePath); - - panel.title = panel.title || getPanelTitle(resource, provider); - panel.webview.options = getWebviewOptions(context, resource); - panel.webview.html = - provider.provideTextDocumentContent(resource, panel.webview); - - _registerPanel({ panel, resource, provider }); - } - }); - } - }; - - _registerCommands(); - _serializePanel(editingProvider); -} - -export function deactivate() {} - -// helper /////// - -function getPanelTitle( - uri: Uri, - _provider: EditingProvider -): string { - - const prefix = 'Edit'; - - return `${prefix}: ${path.basename(uri.fsPath)}`; -} - -function getWebviewOptions(context: ExtensionContext, uri: Uri) { - return { - enableScripts: true, - retainContextWhenHidden: true, - localResourceRoots: getLocalResourceRoots(context, uri) - }; -} - -function getLocalResourceRoots( - context: ExtensionContext, - resource: vscode.Uri -): vscode.Uri[] { - - const baseRoots = [ vscode.Uri.file(context.extensionPath) ]; - const folder = vscode.workspace.getWorkspaceFolder(resource); - - if (folder) { - return baseRoots.concat(folder.uri); - } - - if (!resource.scheme || resource.scheme === 'file') { - return baseRoots.concat(vscode.Uri.file(path.dirname(resource.fsPath))); - } - - return baseRoots; -} - -function getUri(...p: string[]): vscode.Uri { - return vscode.Uri.file(path.join(...p)); -} - -function sendMessage(message: string, webview: Webview) { - webview.postMessage(message); -} +import { BpmnEditor } from './bpmn-editor'; -function getDocumentUri(uri?: Uri) { - const activeEditor = vscode.window.activeTextEditor; +export function activate(context: vscode.ExtensionContext) { - return uri || activeEditor?.document.uri; + // register our custom editor providers + context.subscriptions.push(BpmnEditor.register(context)); } diff --git a/src/features/editing/bpmnModelerBuilder.ts b/src/features/editing/bpmnModelerBuilder.ts deleted file mode 100644 index e09ff48..0000000 --- a/src/features/editing/bpmnModelerBuilder.ts +++ /dev/null @@ -1,161 +0,0 @@ -'use strict'; -export class BpmnModelerBuilder { - contents: string; - resources: any; - - public constructor(contents: string, resources: any) { - this.contents = contents; - this.resources = resources; - } - - private removeNewLines(contents: string): string { - return contents.replace(/(\r\n|\n|\r)/gm, ' '); - } - - private replaceSingleQuotes(contents: string): string { - return contents.replace(/'/gm, '''); - } - - public buildModelerView(): string { - this.contents = this.removeNewLines(this.replaceSingleQuotes(this.contents)); - - const head = ` - - - - - BPMN Modeler - - - - - - - - - - - - - - - - `; - - const body = ` - -
-
-
- -
-
-
-
- - - - `; - - const tail = [ '' ].join('\n'); - - return head + body + tail; - } -} diff --git a/src/features/editing/editingProvider.ts b/src/features/editing/editingProvider.ts deleted file mode 100644 index b4325c3..0000000 --- a/src/features/editing/editingProvider.ts +++ /dev/null @@ -1,71 +0,0 @@ -'use strict'; - -import * as vscode from 'vscode'; - -import * as path from 'node:path'; -import * as fs from 'node:fs'; - -import { BpmnModelerBuilder } from './bpmnModelerBuilder'; - -import Ids = require('ids'); - -const ids = new Ids([ 32, 36, 1 ]); - - -export class EditingProvider { - - public constructor(private _context: vscode.ExtensionContext) { } - - private getUri(webview: vscode.Webview, ...p: string[]): vscode.Uri { - const fileUri = vscode.Uri.file(path.join(this._context.extensionPath, ...p)); - - return webview.asWebviewUri(fileUri); - } - - public provideTextDocumentContent(localResource: vscode.Uri, webview: vscode.Webview): string { - - const localDocumentPath = localResource.fsPath; - - let contents = fs.readFileSync(localDocumentPath, { encoding: 'utf8' }); - - if (contents === '') { - contents = this.getInitialDiagram(); - } - - const builder = new BpmnModelerBuilder(contents, { - modelerDistro: this.getUri(webview, 'node_modules', 'bpmn-js', 'dist', 'bpmn-modeler.development.js'), - diagramStyles: this.getUri(webview, 'node_modules', 'bpmn-js', 'dist', 'assets', 'diagram-js.css'), - bpmnStyles: this.getUri(webview, 'node_modules', 'bpmn-js', 'dist', 'assets', 'bpmn-js.css'), - bpmnFont: this.getUri(webview, 'node_modules', 'bpmn-js', 'dist', 'assets', 'bpmn-font', 'css', 'bpmn.css'), - modelerStyles: this.getUri(webview, 'out', 'assets', 'modeler.css'), - codiconsFont: this.getUri(webview, 'node_modules', '@vscode/codicons', 'dist', 'codicon.css'), - resourceUri: localResource - }); - - return builder.buildModelerView(); - } - - private getInitialDiagram(): string { - const definitionsId = ids.next(), - processId = ids.next(); - - return ` - - - - - - - - - - - -`; - } -} diff --git a/src/features/editing/index.ts b/src/features/editing/index.ts deleted file mode 100644 index 0307c3d..0000000 --- a/src/features/editing/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { EditingProvider } from './editingProvider'; \ No newline at end of file diff --git a/src/util.ts b/src/util.ts new file mode 100644 index 0000000..e169bfc --- /dev/null +++ b/src/util.ts @@ -0,0 +1,8 @@ +export function getNonce() { + let text = ''; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; +}