diff --git a/package-lock.json b/package-lock.json index 6c713457..5134073d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "plugins/importer-postman", "plugins/importer-postman-environment", "plugins/importer-yaak", + "plugins/template-function-1password", "plugins/template-function-cookie", "plugins/template-function-ctx", "plugins/template-function-encode", @@ -39,10 +40,10 @@ "plugins/template-function-random", "plugins/template-function-regex", "plugins/template-function-request", - "plugins/template-function-response", "plugins/template-function-timestamp", "plugins/template-function-uuid", "plugins/template-function-xml", + "plugins/template-function-response", "plugins/themes-yaak", "src-tauri", "src-tauri/yaak-crypto", @@ -83,6 +84,21 @@ "workspaces-run": "^1.0.2" } }, + "node_modules/@1password/sdk": { + "version": "0.4.0-beta.2", + "resolved": "https://registry.npmjs.org/@1password/sdk/-/sdk-0.4.0-beta.2.tgz", + "integrity": "sha512-holD+X6kKTe9K6iX5AcHGXfTYdikSJosZVXQa6MPLAP/a5HiELnHAOtJOFoYgXw0oA31d727qO6n9/4MnsQOUg==", + "license": "MIT", + "dependencies": { + "@1password/sdk-core": "0.4.0-beta.2" + } + }, + "node_modules/@1password/sdk-core": { + "version": "0.4.0-beta.2", + "resolved": "https://registry.npmjs.org/@1password/sdk-core/-/sdk-core-0.4.0-beta.2.tgz", + "integrity": "sha512-GWz/EJ5NKfiXI9WfL2nTHvTfI1e1X8YaUE2JAGoI/in/Vn4tp/PyuH2sqWt0Vh9P5Edn04lrEBcl+mEHUo0EyQ==", + "license": "MIT" + }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -4341,6 +4357,10 @@ "resolved": "plugins/importer-yaak", "link": true }, + "node_modules/@yaak/template-function-1password": { + "resolved": "plugins/template-function-1password", + "link": true + }, "node_modules/@yaak/template-function-cookie": { "resolved": "plugins/template-function-cookie", "link": true @@ -5004,6 +5024,19 @@ "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", "license": "MIT" }, + "node_modules/async-each": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.6.tgz", + "integrity": "sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, "node_modules/async-function": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", @@ -5129,6 +5162,17 @@ "@babel/types": "^7.23.6" } }, + "node_modules/babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" + } + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", @@ -5226,6 +5270,17 @@ "node": ">=10" } }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, "node_modules/bl": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", @@ -6076,6 +6131,15 @@ "toggle-selection": "^1.0.6" } }, + "node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.", + "dev": true, + "hasInstallScript": true, + "license": "MIT" + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -6157,6 +6221,579 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/cpx": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cpx/-/cpx-1.5.0.tgz", + "integrity": "sha512-jHTjZhsbg9xWgsP2vuNW2jnnzBX+p4T+vNI9Lbjzs1n4KhOfa22bQppiFYLsWQKd8TzmL5aSP/Me3yfsCwXbDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-runtime": "^6.9.2", + "chokidar": "^1.6.0", + "duplexer": "^0.1.1", + "glob": "^7.0.5", + "glob2base": "^0.0.12", + "minimatch": "^3.0.2", + "mkdirp": "^0.5.1", + "resolve": "^1.1.7", + "safe-buffer": "^5.0.1", + "shell-quote": "^1.6.1", + "subarg": "^1.0.0" + }, + "bin": { + "cpx": "bin/index.js" + } + }, + "node_modules/cpx/node_modules/anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "license": "ISC", + "dependencies": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "node_modules/cpx/node_modules/arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha512-dtXTVMkh6VkEEA7OhXnN1Ecb8aAGFdZ1LFxtOCoqj4qkyOJMt7+qs6Ahdy6p/NQCPYsRSXXivhSB/J5E9jmYKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha512-G2n5bG5fSUCpnsXz4+8FUkYsGPkNfLn9YvS66U5qbTIXI2Ynnlo4Bi42bWv+omKUCqz+ejzfClwne0alJWJPhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha512-xU7bpz2ytJl1bH9cgIurjpg/n8Gohy9GTw81heDYLJQ4RU60dlyJsa+atVF2pI0yMMvKxI9HkKwjePCj5XI1hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha512-mk8fAWcRUOxY7btlLtitj3A45jOwSAxH4tOFOoEGbVsl6cL6pPMWUy7dwZ/canfj3QEdP6FHSnf/l1c6/WkzVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + }, + "optionalDependencies": { + "fsevents": "^1.0.0" + } + }, + "node_modules/cpx/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/cpx/node_modules/expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha512-hxx03P2dJxss6ceIeri9cmYOT4SRs3Zk3afZwWpOsRqLqprhTR8u++SlC+sFGsQr7WGFPdMF7Gjc1njDLDK6UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-posix-bracket": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha512-1FOj1LOwn42TMrruOHGt18HemVnbwAmAak7krWk+wa93KXxGbK+2jpezm+ytJYDaBX0/SPLZFHKM7m+tKobWGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "Upgrade to fsevents v2 to mitigate potential security issues", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/cpx/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cpx/node_modules/glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^2.0.0" + } + }, + "node_modules/cpx/node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha512-LnU2XFEk9xxSJ6rfgAry/ty5qwUTyHYOBU0g4R6tIw5ljwgGIBmiKhRWLw5NpMOnrgUNcDJ4WMp8rl3sYVHLNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/cpx/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cpx/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/expand-brackets/node_modules/is-descriptor": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.7.tgz", + "integrity": "sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.1", + "is-data-descriptor": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/readdirp/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cpx/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/cpy": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/cpy/-/cpy-10.1.0.tgz", @@ -6901,6 +7538,13 @@ "node": ">= 0.4" } }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true, + "license": "MIT" + }, "node_modules/duplexer2": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", @@ -7889,6 +8533,82 @@ "dev": true, "license": "MIT" }, + "node_modules/expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha512-AFASGfIlnIbkKPQwX1yHaDjFvh/1gyKJODme52V6IORh69uEYgZp0o9C+qsIGNVEiuuhQU0CSSl++Rlegg1qvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha512-QUzH43Gfb9+5yckcrSA0VBDwEtDUchrk4F6tfJZQuNzDJbEDB9cZNzSfXGQ1jqmdDY/kl41lUOWM9syA8z8jlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/expand-range/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-range/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/expect-type": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", @@ -8119,6 +8839,24 @@ "node": ">=4" } }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha512-BTCqyBaWBTsauvnHiE8i562+EdJj+oUpkqWp2R1iCoR8f6oo8STRu3of7WJJ0TqWtxN50a5YFpzYK4Jj9esYfQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -8131,6 +8869,13 @@ "node": ">=8" } }, + "node_modules/find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==", + "dev": true, + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -8240,6 +8985,19 @@ "node": ">=0.10.0" } }, + "node_modules/for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/foreach": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.6.tgz", @@ -8683,6 +9441,53 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha512-ab1S1g1EbO7YzauaJLkgLp7DZVAqj9M/dvKlTt8DkXA2tiOIcSMrlVI2J1RZyB5iJVccEscjGn+kpOG9788MHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-base/node_modules/glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha512-JDYOvfxio/t42HKdxkAYaCiBN7oYiuxykOxKxdaUW5Qn0zaYN3gRQWolrwdnf0shM9/EP0ebuuTmyoXNr1cC5w==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^2.0.0" + } + }, + "node_modules/glob-base/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob-base/node_modules/is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -8729,6 +9534,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha512-ZyqlgowMbfj2NPjxaZZ/EtsXlOch28FRXgMd64vqZWk1bT9+wvSRLYD1om9M7QfQru51zJPAT17qXm4/zd+9QA==", + "dev": true, + "dependencies": { + "find-index": "^0.1.1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -9930,6 +10747,29 @@ "node": ">= 0.4" } }, + "node_modules/is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha512-9YclgOGtN/f8zx0Pr4FQYMdibBiTaH3sn52vjYip4ZSf6C4/6RfTEZ+MR4GvKhCxdPh21Bg42/WL55f6KSnKpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha512-0EygVC5qPvIyb+gSz7zdD5/AAoS6Qrx1e//6N4yv4oNm30kqvdmG66oZFWVlQHUWe5OjP08FuTw2IdT0EOTcYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-primitive": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", @@ -10117,6 +10957,26 @@ "node": ">=0.10.0" } }, + "node_modules/is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha512-Yu68oeXJ7LeWNmZ3Zov/xg/oDBnBK2RNxwYY1ilNJX+tKKZqgPK+qOn/Gs9jEu66KDY9Netf5XLKNGzas/vPfQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha512-N3w1tFaRfk3UrPfqeRyD+GYDASU3W5VinKhlORy8EWVf/sIdDL9GAcew85XmktCfH+ngG7SRXEVDoO18WMdB/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -11259,6 +12119,13 @@ "node": ">= 0.4" } }, + "node_modules/math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "dev": true, + "license": "MIT" + }, "node_modules/mdast-util-find-and-replace": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", @@ -12495,6 +13362,14 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.1.tgz", + "integrity": "sha512-r7bBUGKzlqk8oPBDYxt6Z0aEdF1G1rwlMcLk8LCOMbOzf0mG+JUfUzG4fIMWwHWP0iyaLWEQZJmtB7nOHEm/qw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/nano-css": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/nano-css/-/nano-css-5.6.2.tgz", @@ -13477,6 +14352,30 @@ "node": ">= 0.4" } }, + "node_modules/object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha512-UiAM5mhmIuKLsOvrL+B0U2d1hXHF3bFYWIuH1LMpuV2EJEHG1Ntz06PgLEHjm6VFd87NpH8rastvPoyv6UW2fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.omit/node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -13885,6 +14784,45 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, + "node_modules/parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha512-FC5TeK0AwXzq3tUBFtH74naWkPQCEWs4K+xMxWZBlKDWu0bVHXGZa+KKqxKidd7xwhdZ19ZNuF2uO1M/r196HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-glob/node_modules/is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-glob/node_modules/is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -14456,6 +15394,16 @@ "node": ">= 0.8.0" } }, + "node_modules/preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha512-s/46sYeylUfHNjI+sA/78FAHlmIuKqI9wNnzEOGehAlUUYeObv5C2mOinXBjyUyWmJ2SfcS2/ydApH4hTF4WXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prettier": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", @@ -14568,6 +15516,31 @@ "node": ">=0.12" } }, + "node_modules/randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/randomatic/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -15126,6 +16099,26 @@ "url": "https://github.com/Mermade/oas-kit?sponsor=1" } }, + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-equal-shallow": "^0.1.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -15257,6 +16250,13 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true, + "license": "ISC" + }, "node_modules/repeat-element": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", @@ -16788,6 +17788,16 @@ "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", "license": "MIT" }, + "node_modules/subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha512-RIrIdRY0X1xojthNcVtgT9sjpOGagEUKpZdgBUi054OEPFo282yg+zE+t1Rj3+RqKq2xStL7uUHhY+AjbC4BXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.1.0" + } + }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", @@ -19098,6 +20108,16 @@ "name": "@yaak/importer-yaak", "version": "0.1.0" }, + "plugins/template-function-1password": { + "name": "@yaak/template-function-1password", + "version": "0.1.0", + "dependencies": { + "@1password/sdk": "^0.4.0-beta.2" + }, + "devDependencies": { + "cpx": "^1.5.0" + } + }, "plugins/template-function-cookie": { "name": "@yaak/template-function-cookie", "version": "0.1.0" diff --git a/package.json b/package.json index 18df4621..85d68672 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "plugins/importer-postman", "plugins/importer-postman-environment", "plugins/importer-yaak", + "plugins/template-function-1password", "plugins/template-function-cookie", "plugins/template-function-ctx", "plugins/template-function-encode", diff --git a/packages/plugin-runtime/src/PluginInstance.ts b/packages/plugin-runtime/src/PluginInstance.ts index bb969cb3..056f0ddb 100644 --- a/packages/plugin-runtime/src/PluginInstance.ts +++ b/packages/plugin-runtime/src/PluginInstance.ts @@ -25,7 +25,11 @@ import { Context, PluginDefinition } from '@yaakapp/api'; import console from 'node:console'; import { type Stats, statSync, watch } from 'node:fs'; import path from 'node:path'; -import { applyDynamicFormInput, applyFormInputDefaults } from './common'; +import { + applyDynamicFormInput, + applyFormInputDefaults, + validateTemplateFunctionArgs, +} from './common'; import { EventChannel } from './EventChannel'; import { migrateTemplateFunctionSelectOptions } from './migrations'; @@ -334,15 +338,22 @@ export class PluginInstance { ); } else if (typeof fn?.onRender === 'function') { const resolvedArgs = await applyDynamicFormInput(ctx, fn.args, payload.args); - payload.args.values = applyFormInputDefaults(resolvedArgs, payload.args.values); - try { - const result = await fn.onRender(ctx, payload.args); + const values = applyFormInputDefaults(resolvedArgs, payload.args.values); + const error = validateTemplateFunctionArgs(fn.name, resolvedArgs, values); + if (error && payload.args.purpose !== 'preview') { this.#sendPayload( context, - { - type: 'call_template_function_response', - value: result ?? null, - }, + { type: 'call_template_function_response', value: null, error }, + replyId, + ); + return; + } + + try { + const result = await fn.onRender(ctx, { ...payload.args, values }); + this.#sendPayload( + context, + { type: 'call_template_function_response', value: result ?? null }, replyId, ); } catch (err) { diff --git a/packages/plugin-runtime/src/common.ts b/packages/plugin-runtime/src/common.ts index be2929fb..80196d91 100644 --- a/packages/plugin-runtime/src/common.ts +++ b/packages/plugin-runtime/src/common.ts @@ -48,9 +48,36 @@ export async function applyDynamicFormInput( ...(typeof dynamic === 'function' ? await dynamic(ctx, callArgs as any) : undefined), }; if ('inputs' in newArg && Array.isArray(newArg.inputs)) { - newArg.inputs = await applyDynamicFormInput(ctx, newArg.inputs, callArgs as any); + try { + newArg.inputs = await applyDynamicFormInput(ctx, newArg.inputs, callArgs as any); + } catch (e) { + console.error('Failed to apply dynamic form input', e); + } } resolvedArgs.push(newArg); } return resolvedArgs; } + +export function validateTemplateFunctionArgs( + fnName: string, + args: TemplateFunctionArg[], + values: CallTemplateFunctionArgs['values'], +): string | null { + for (const arg of args) { + if ('inputs' in arg && arg.inputs) { + // Recurse down + const err = validateTemplateFunctionArgs(fnName, arg.inputs, values); + if (err) return err; + } + if (!('name' in arg)) continue; + if (arg.optional) continue; + if (arg.defaultValue != null) continue; + if (arg.hidden) continue; + if (values[arg.name] != null) continue; + + return `Missing required argument "${arg.label || arg.name}" for template function ${fnName}()`; + } + + return null; +} diff --git a/plugins/template-function-1password/package.json b/plugins/template-function-1password/package.json new file mode 100644 index 00000000..446b2ef9 --- /dev/null +++ b/plugins/template-function-1password/package.json @@ -0,0 +1,20 @@ +{ + "name": "@yaak/template-function-1password", + "displayName": "1Password Template Functions", + "description": "Template function for accessing 1Password secrets", + "private": true, + "version": "0.1.0", + "scripts": { + "build": "run-p build:*", + "build:1-build": "yaakcli build", + "build:2-cpywasm": "cpx '../../node_modules/@1password/sdk-core/nodejs/core_bg.*' build/", + "dev": "yaakcli dev", + "lint": "tsc --noEmit && eslint . --ext .ts,.tsx" + }, + "dependencies": { + "@1password/sdk": "^0.4.0-beta.2" + }, + "devDependencies": { + "cpx": "^1.5.0" + } +} diff --git a/plugins/template-function-1password/src/index.ts b/plugins/template-function-1password/src/index.ts new file mode 100644 index 00000000..5e9d6e4b --- /dev/null +++ b/plugins/template-function-1password/src/index.ts @@ -0,0 +1,123 @@ +import type { Client } from '@1password/sdk'; +import { createClient } from '@1password/sdk'; +import type { CallTemplateFunctionArgs } from '@yaakapp-internal/plugins'; +import type { PluginDefinition } from '@yaakapp/api'; +import crypto from 'crypto'; + +const _clients: Record = {}; + +async function op(args: CallTemplateFunctionArgs): Promise { + const token = args.values.token; + if (typeof token !== 'string') return null; + + const tokenHash = crypto.createHash('sha256').update(token).digest('hex'); + try { + _clients[tokenHash] ??= await createClient({ + auth: token, + integrationName: 'Yaak 1Password Plugin', + integrationVersion: 'v1.0.0', + }); + } catch { + return null; + } + return _clients[tokenHash]; +} + +export const plugin: PluginDefinition = { + templateFunctions: [ + { + name: '1password.item', + description: 'Get a secret', + args: [ + { + name: 'token', + type: 'text', + label: '1Password Service Account Token', + description: '', + defaultValue: '${[ONEPASSWORD_TOKEN]}', + password: true, + }, + { + name: 'vault', + label: 'Vault', + type: 'select', + options: [], + async dynamic(_ctx, args) { + const client = await op(args); + if (client == null) return { hidden: true }; + // Fetches a secret. + const vaults = await client.vaults.list({ decryptDetails: true }); + return { + options: vaults.map((vault) => ({ + label: `${vault.title} (${vault.activeItemCount} Items)`, + value: vault.id, + })), + }; + }, + }, + { + name: 'item', + label: 'Item', + type: 'select', + options: [], + async dynamic(_ctx, args) { + const client = await op(args); + if (client == null) return { hidden: true }; + const vaultId = args.values.vault; + if (typeof vaultId !== 'string') return { hidden: true }; + + const items = await client.items.list(vaultId); + return { + options: items.map((item) => ({ + label: item.title + ' ' + item.category, + value: item.id, + })), + }; + }, + }, + { + name: 'field', + label: 'Field', + type: 'select', + options: [], + async dynamic(_ctx, args) { + const client = await op(args); + if (client == null) return { hidden: true }; + const vaultId = args.values.vault; + const itemId = args.values.item; + if (typeof vaultId !== 'string' || typeof itemId !== 'string') { + return { hidden: true }; + } + + const item = await client.items.get(vaultId, itemId); + + return { + options: item.fields.map((field) => ({ label: field.title, value: field.id })), + }; + }, + }, + ], + async onRender(_ctx, args) { + const client = await op(args); + if (client == null) throw new Error('Invalid token'); + const vaultId = args.values.vault; + const itemId = args.values.item; + const fieldId = args.values.field; + if ( + typeof vaultId !== 'string' || + typeof itemId !== 'string' || + typeof fieldId !== 'string' + ) { + return null; + } + + const item = await client.items.get(vaultId, itemId); + const field = item.fields.find((f) => f.id === fieldId); + if (field == null) { + throw new Error('Field not found: ' + fieldId); + } + return field.value ?? ''; + }, + }, + ], +}; diff --git a/plugins/template-function-1password/tsconfig.json b/plugins/template-function-1password/tsconfig.json new file mode 100644 index 00000000..4082f16a --- /dev/null +++ b/plugins/template-function-1password/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../../tsconfig.json" +} diff --git a/plugins/template-function-request/src/index.ts b/plugins/template-function-request/src/index.ts index 39452b83..24a16913 100755 --- a/plugins/template-function-request/src/index.ts +++ b/plugins/template-function-request/src/index.ts @@ -1,4 +1,5 @@ import type { AnyModel, HttpUrlParameter } from '@yaakapp-internal/models'; +import type { GenericCompletionOption } from '@yaakapp-internal/plugins'; import type { CallTemplateFunctionArgs, Context, PluginDefinition } from '@yaakapp/api'; export const plugin: PluginDefinition = { @@ -36,6 +37,21 @@ export const plugin: PluginDefinition = { name: 'header', label: 'Header Name', type: 'text', + async dynamic(ctx, args) { + if (typeof args.values.requestId !== 'string') return null; + + const request = await ctx.httpRequest.getById({ id: args.values.requestId }); + if (request == null) return null; + + const validHeaders = request.headers.filter(h => h.enabled !== false && h.name); + return { + placeholder: validHeaders[0]?.name, + completionOptions: validHeaders.map((h) => ({ + label: h.name, + type: 'constant', + })), + }; + }, }, ], async onRender(ctx: Context, args: CallTemplateFunctionArgs): Promise { diff --git a/plugins/template-function-response/src/index.ts b/plugins/template-function-response/src/index.ts index a9358bd4..054c93b6 100644 --- a/plugins/template-function-response/src/index.ts +++ b/plugins/template-function-response/src/index.ts @@ -1,3 +1,4 @@ +import type { GenericCompletionOption } from '@yaakapp-internal/plugins'; import type { JSONPathResult } from '../../template-function-json'; import { filterJSONPath } from '../../template-function-json'; import type { XPathResult } from '../../template-function-xml'; @@ -68,7 +69,22 @@ export const plugin: PluginDefinition = { type: 'text', name: 'header', label: 'Header Name', - placeholder: 'Content-Type', + async dynamic(ctx, args) { + const response = await getResponse(ctx, { + requestId: String(args.values.request || ''), + purpose: args.purpose, + behavior: args.values.behavior ? String(args.values.behavior) : null, + ttl: String(args.values.ttl || ''), + }); + + return { + placeholder: response?.headers[0]?.name, + completionOptions: response?.headers.map((h) => ({ + label: h.name, + type: 'constant', + })), + }; + }, }, ], async onRender(ctx: Context, args: CallTemplateFunctionArgs): Promise { diff --git a/scripts/vendor-plugins.cjs b/scripts/vendor-plugins.cjs index 81361ae9..0e099165 100644 --- a/scripts/vendor-plugins.cjs +++ b/scripts/vendor-plugins.cjs @@ -11,5 +11,5 @@ for (const name of readdirSync(pluginsDir)) { const destDir = path.join(__dirname, '../src-tauri/vendored/plugins/', name); console.log(`Copying ${name} to ${destDir}`); cpSync(path.join(dir, 'package.json'), path.join(destDir, 'package.json')); - cpSync(path.join(dir, 'build/index.js'), path.join(destDir, 'build/index.js')); + cpSync(path.join(dir, 'build'), path.join(destDir, 'build'), { recursive: true }); } diff --git a/src-tauri/yaak-templates/src/parser.rs b/src-tauri/yaak-templates/src/parser.rs index 2d74cb50..f1d3e6e2 100644 --- a/src-tauri/yaak-templates/src/parser.rs +++ b/src-tauri/yaak-templates/src/parser.rs @@ -335,7 +335,7 @@ impl Parser { while self.pos < self.chars.len() { let ch = self.peek_char(); let is_valid = if start_pos == self.pos { - ch.is_alphabetic() || ch == '_' // First is more restrictive + ch.is_alphanumeric() || ch == '_' // The first char is more restrictive } else { ch.is_alphanumeric() || ch == '_' || ch == '-' }; diff --git a/src-web/components/TemplateFunctionDialog.tsx b/src-web/components/TemplateFunctionDialog.tsx index 33489732..b86f10c0 100644 --- a/src-web/components/TemplateFunctionDialog.tsx +++ b/src-web/components/TemplateFunctionDialog.tsx @@ -1,3 +1,4 @@ +import type { EditorView } from '@codemirror/view'; import type { Folder, GrpcRequest, @@ -5,10 +6,12 @@ import type { WebsocketRequest, Workspace, } from '@yaakapp-internal/models'; -import type { FormInput, TemplateFunction } from '@yaakapp-internal/plugins'; +import type { TemplateFunction } from '@yaakapp-internal/plugins'; import type { FnArg, Tokens } from '@yaakapp-internal/templates'; +import { parseTemplate } from '@yaakapp-internal/templates'; import classNames from 'classnames'; import { useEffect, useMemo, useState } from 'react'; +import { activeWorkspaceAtom } from '../hooks/useActiveWorkspace'; import { useDebouncedValue } from '../hooks/useDebouncedValue'; import { useRenderTemplate } from '../hooks/useRenderTemplate'; import { useTemplateFunctionConfig } from '../hooks/useTemplateFunctionConfig'; @@ -17,14 +20,17 @@ import { useTemplateTokensToString, } from '../hooks/useTemplateTokensToString'; import { useToggle } from '../hooks/useToggle'; +import { showDialog } from '../lib/dialog'; import { convertTemplateToInsecure } from '../lib/encryption'; +import { jotaiStore } from '../lib/jotai'; import { setupOrConfigureEncryption } from '../lib/setupOrConfigureEncryption'; import { Button } from './core/Button'; +import { collectArgumentValues } from './core/Editor/twig/util'; import { IconButton } from './core/IconButton'; import { InlineCode } from './core/InlineCode'; import { LoadingIcon } from './core/LoadingIcon'; import { PlainInput } from './core/PlainInput'; -import { HStack, VStack } from './core/Stacks'; +import { HStack } from './core/Stacks'; import { DYNAMIC_FORM_NULL_ARG, DynamicForm } from './DynamicForm'; interface Props { @@ -115,7 +121,7 @@ function InitializedTemplateFunctionDialog({ }, [argValues, name]); const tagText = useTemplateTokensToString(tokens); - const templateFunction = useTemplateFunctionConfig(name, argValues, model).data; + const templateFunction = useTemplateFunctionConfig(name, argValues, model); const handleDone = () => { if (tagText.data) { @@ -136,7 +142,7 @@ function InitializedTemplateFunctionDialog({ const tooLarge = rendered.data ? rendered.data.length > 10000 : false; const dataContainsSecrets = useMemo(() => { for (const [name, value] of Object.entries(argValues)) { - const arg = templateFunction?.args.find((a) => 'name' in a && a.name === name); + const arg = templateFunction.data?.args.find((a) => 'name' in a && a.name === name); const isTextPassword = arg?.type === 'text' && arg.password; if (isTextPassword && typeof value === 'string' && value && rendered.data?.includes(value)) { return true; @@ -147,7 +153,13 @@ function InitializedTemplateFunctionDialog({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [rendered.data]); - if (templateFunction == null) return null; + if (templateFunction.data == null || templateFunction.isPending) { + return ( +
+ +
+ ); + } return (
)}
{previewType !== 'none' ? ( - +
Rendered Preview @@ -202,7 +214,7 @@ function InitializedTemplateFunctionDialog({ @@ -219,25 +231,25 @@ function InitializedTemplateFunctionDialog({ ) : ( rendered.data || <>  )} -
+
{ setRenderKey(new Date().toISOString()); }} />
- +
) : ( )}
- {templateFunction.name === 'secure' && ( + {templateFunction.data.name === 'secure' && ( @@ -251,37 +263,35 @@ function InitializedTemplateFunctionDialog({ ); } -/** - * Process the initial tokens from the template and merge those with the default values pulled from - * the template function definition. - */ -function collectArgumentValues(initialTokens: Tokens, templateFunction: TemplateFunction) { - const initial: Record = {}; - const initialArgs = - initialTokens.tokens[0]?.type === 'tag' && initialTokens.tokens[0]?.val.type === 'fn' - ? initialTokens.tokens[0]?.val.args - : []; - - const processArg = (arg: FormInput) => { - if ('inputs' in arg && arg.inputs) { - arg.inputs.forEach(processArg); - } - if (!('name' in arg)) return; - - const initialArg = initialArgs.find((a) => a.name === arg.name); - const initialArgValue = - initialArg?.value.type === 'str' - ? initialArg?.value.text - : initialArg?.value.type === 'bool' - ? initialArg.value.value - : undefined; - const value = initialArgValue ?? arg.defaultValue; - if (value != null) { - initial[arg.name] = value; - } - }; - - templateFunction.args.forEach(processArg); - - return initial; -} +TemplateFunctionDialog.show = function ( + fn: TemplateFunction, + tagValue: string, + startPos: number, + view: EditorView, +) { + const initialTokens = parseTemplate(tagValue); + showDialog({ + id: 'template-function-' + Math.random(), // Allow multiple at once + size: 'md', + className: 'h-[60rem]', + noPadding: true, + title: {fn.name}(…), + description: fn.description, + render: ({ hide }) => { + const model = jotaiStore.get(activeWorkspaceAtom)!; + return ( + { + view.dispatch({ + changes: [{ from: startPos, to: startPos + tagValue.length, insert }], + }); + }} + /> + ); + }, + }); +}; diff --git a/src-web/components/core/Editor/Editor.tsx b/src-web/components/core/Editor/Editor.tsx index 07a9aa63..1d2b24ee 100644 --- a/src-web/components/core/Editor/Editor.tsx +++ b/src-web/components/core/Editor/Editor.tsx @@ -10,7 +10,6 @@ import { vscodeKeymap } from '@replit/codemirror-vscode-keymap'; import type { EditorKeymap } from '@yaakapp-internal/models'; import { settingsAtom } from '@yaakapp-internal/models'; import type { EditorLanguage, TemplateFunction } from '@yaakapp-internal/plugins'; -import { parseTemplate } from '@yaakapp-internal/templates'; import classNames from 'classnames'; import type { GraphQLSchema } from 'graphql'; import { useAtomValue } from 'jotai'; @@ -27,20 +26,17 @@ import { useRef, } from 'react'; import { activeEnvironmentAtom } from '../../../hooks/useActiveEnvironment'; -import { activeWorkspaceAtom } from '../../../hooks/useActiveWorkspace'; import type { WrappedEnvironmentVariable } from '../../../hooks/useEnvironmentVariables'; import { useEnvironmentVariables } from '../../../hooks/useEnvironmentVariables'; import { useRandomKey } from '../../../hooks/useRandomKey'; import { useRequestEditor } from '../../../hooks/useRequestEditor'; import { useTemplateFunctionCompletionOptions } from '../../../hooks/useTemplateFunctions'; -import { showDialog } from '../../../lib/dialog'; import { editEnvironment } from '../../../lib/editEnvironment'; import { tryFormatJson, tryFormatXml } from '../../../lib/formatters'; import { jotaiStore } from '../../../lib/jotai'; import { withEncryptionEnabled } from '../../../lib/setupOrConfigureEncryption'; import { TemplateFunctionDialog } from '../../TemplateFunctionDialog'; import { IconButton } from '../IconButton'; -import { InlineCode } from '../InlineCode'; import { HStack } from '../Stacks'; import './Editor.css'; import { @@ -285,32 +281,10 @@ export function Editor({ const onClickFunction = useCallback( async (fn: TemplateFunction, tagValue: string, startPos: number) => { - const initialTokens = parseTemplate(tagValue); - const show = () => - showDialog({ - id: 'template-function-' + Math.random(), // Allow multiple at once - size: 'md', - className: 'h-[90vh] max-h-[60rem]', - noPadding: true, - title: {fn.name}(…), - description: fn.description, - render: ({ hide }) => { - const model = jotaiStore.get(activeWorkspaceAtom)!; - return ( - { - cm.current?.view.dispatch({ - changes: [{ from: startPos, to: startPos + tagValue.length, insert }], - }); - }} - /> - ); - }, - }); + const show = () => { + if (cm.current === null) return; + TemplateFunctionDialog.show(fn, tagValue, startPos, cm.current.view); + }; if (fn.name === 'secure') { withEncryptionEnabled(show); diff --git a/src-web/components/core/Editor/genericCompletion.ts b/src-web/components/core/Editor/genericCompletion.ts index cf1206a0..bfdecef2 100644 --- a/src-web/components/core/Editor/genericCompletion.ts +++ b/src-web/components/core/Editor/genericCompletion.ts @@ -1,5 +1,6 @@ import type { CompletionContext } from '@codemirror/autocomplete'; import type { GenericCompletionOption } from '@yaakapp-internal/plugins'; +import { defaultBoost } from './twig/completion'; export interface GenericCompletionConfig { minMatch?: number; @@ -23,7 +24,12 @@ export function genericCompletion(config?: GenericCompletionConfig) { const matchedMinimumLength = toMatch.to - toMatch.from >= minMatch; if (!matchedMinimumLength && !context.explicit) return null; - const optionsWithoutExactMatches = options.filter((o) => o.label !== toMatch.text); + const optionsWithoutExactMatches = options + .filter((o) => o.label !== toMatch.text) + .map((o) => ({ + ...o, + boost: defaultBoost(o), + })); return { validFor: () => true, // Not really sure why this is all it needs from: toMatch.from, diff --git a/src-web/components/core/Editor/twig/completion.ts b/src-web/components/core/Editor/twig/completion.ts index b05e865c..f7fdd4d2 100644 --- a/src-web/components/core/Editor/twig/completion.ts +++ b/src-web/components/core/Editor/twig/completion.ts @@ -1,4 +1,6 @@ import type { Completion, CompletionContext } from '@codemirror/autocomplete'; +import { startCompletion } from '@codemirror/autocomplete'; +import type { TemplateFunction } from '@yaakapp-internal/plugins'; const openTag = '${[ '; const closeTag = ' ]}'; @@ -11,9 +13,7 @@ export type TwigCompletionOptionNamespace = { type: 'namespace'; }; -export type TwigCompletionOptionFunction = { - args: { name: string }[]; - aliases?: string[]; +export type TwigCompletionOptionFunction = TemplateFunction & { type: 'function'; }; @@ -34,32 +34,24 @@ export interface TwigCompletionConfig { options: TwigCompletionOption[]; } -const MIN_MATCH_VAR = 1; -const MIN_MATCH_NAME = 1; +const MIN_MATCH_NAME = 2; export function twigCompletion({ options }: TwigCompletionConfig) { return function completions(context: CompletionContext) { const toStartOfName = context.matchBefore(/[\w_.]*/); - const toStartOfVariable = context.matchBefore(/\$\{?\[?\s*[\w_]*/); - const toMatch = toStartOfVariable ?? toStartOfName ?? null; + const toMatch = toStartOfName ?? null; if (toMatch === null) return null; const matchLen = toMatch.to - toMatch.from; - const failedVarLen = toStartOfVariable !== null && matchLen < MIN_MATCH_VAR; - if (failedVarLen && !context.explicit) { - return null; - } - - const failedNameLen = toStartOfVariable === null && matchLen < MIN_MATCH_NAME; - if (failedNameLen && !context.explicit) { + if (toMatch.from >0 && matchLen < MIN_MATCH_NAME) { return null; } const completions: Completion[] = options .flatMap((o): Completion[] => { - const matchSegments = toStartOfName!.text.split('.'); + const matchSegments = toMatch!.text.replace(/^\$/, '').split('.'); const optionSegments = o.name.split('.'); // If not on the last segment, only complete the namespace @@ -68,8 +60,17 @@ export function twigCompletion({ options }: TwigCompletionConfig) { return [ { label: prefix + '.*', - apply: prefix, type: 'namespace', + detail: 'namespace', + apply: (view, _completion, from, to) => { + const insert = `${prefix}.`; + view.dispatch({ + changes: { from, to, insert: insert }, + selection: { anchor: from + insert.length }, + }); + // Leave the autocomplete open so the user can continue typing the rest of the namespace + startCompletion(view); + }, }, ]; } @@ -79,24 +80,49 @@ export function twigCompletion({ options }: TwigCompletionConfig) { return [ { label: o.name, - apply: openTag + inner + closeTag, info: o.description, detail: o.type, type: o.type === 'variable' ? 'variable' : 'function', + apply: (view, _completion, from, to) => { + const insert = openTag + inner + closeTag; + view.dispatch({ + changes: { from, to, insert: insert }, + selection: { anchor: from + insert.length }, + }); + }, }, ]; }) .filter((v) => v != null); - // TODO: Figure out how to make autocomplete stay open if opened explicitly. It sucks when you explicitly - // open it, then it closes when you type the next character. + const uniqueCompletions = uniqueBy(completions, 'label'); + const sortedCompletions = uniqueCompletions.sort((a, b) => { + const boostDiff = defaultBoost(b) - defaultBoost(a); + if (boostDiff !== 0) return boostDiff; + return a.label.localeCompare(b.label); + }); + return { + matchLen, validFor: () => true, // Not really sure why this is all it needs from: toMatch.from, - matchLen, - options: completions - // Filter out exact matches - .filter((o) => o.label !== toMatch.text), + options: sortedCompletions, }; }; } + +export function uniqueBy(arr: T[], key: K): T[] { + const map = new Map(); + for (const item of arr) { + map.set(item[key], item); // overwrites → keeps last + } + return [...map.values()]; +} + +export function defaultBoost(o: Completion) { + if (o.type === 'variable') return 4; + if (o.type === 'constant') return 3; + if (o.type === 'function') return 2; + if (o.type === 'namespace') return 1; + return 0; +} diff --git a/src-web/components/core/Editor/twig/templateTags.ts b/src-web/components/core/Editor/twig/templateTags.ts index c51291de..27f69c84 100644 --- a/src-web/components/core/Editor/twig/templateTags.ts +++ b/src-web/components/core/Editor/twig/templateTags.ts @@ -3,7 +3,9 @@ import type { Range } from '@codemirror/state'; import type { DecorationSet, ViewUpdate } from '@codemirror/view'; import { Decoration, ViewPlugin, WidgetType, EditorView } from '@codemirror/view'; import type { SyntaxNodeRef } from '@lezer/common'; +import { parseTemplate } from '@yaakapp-internal/templates'; import type { TwigCompletionOption } from './completion'; +import { collectArgumentValues } from './util'; class TemplateTagWidget extends WidgetType { readonly #clickListenerCallback: () => void; @@ -40,10 +42,7 @@ class TemplateTagWidget extends WidgetType { }`; elt.title = this.option.invalid ? 'Not Found' : (this.option.value ?? ''); elt.setAttribute('data-tag-type', this.option.type); - elt.textContent = - this.option.type === 'function' - ? `${this.option.name}(${this.option.args.length ? '…' : ''})` - : this.option.name; + elt.textContent = this.option.label; elt.addEventListener('click', this.#clickListenerCallback); return elt; } @@ -107,7 +106,20 @@ function templateTags( }; } - const widget = new TemplateTagWidget(option, rawTag, node.from); + let invalid = false; + if (option.type === 'function') { + const tokens = parseTemplate(rawTag); + const values = collectArgumentValues(tokens, option); + for (const arg of option.args) { + if (!('optional' in arg)) continue; + if (!arg.optional && values[arg.name] == null) { + invalid = true; + break; + } + } + } + + const widget = new TemplateTagWidget({ ...option, invalid }, rawTag, node.from); const deco = Decoration.replace({ widget, inclusive: true }); widgets.push(deco.range(node.from, node.to)); } diff --git a/src-web/components/core/Editor/twig/util.ts b/src-web/components/core/Editor/twig/util.ts new file mode 100644 index 00000000..37d6efd1 --- /dev/null +++ b/src-web/components/core/Editor/twig/util.ts @@ -0,0 +1,37 @@ +import type { FormInput, TemplateFunction } from '@yaakapp-internal/plugins'; +import type { Tokens } from '@yaakapp-internal/templates'; + +/** + * Process the initial tokens from the template and merge those with the default values pulled from + * the template function definition. + */ +export function collectArgumentValues(initialTokens: Tokens, templateFunction: TemplateFunction) { + const initial: Record = {}; + const initialArgs = + initialTokens.tokens[0]?.type === 'tag' && initialTokens.tokens[0]?.val.type === 'fn' + ? initialTokens.tokens[0]?.val.args + : []; + + const processArg = (arg: FormInput) => { + if ('inputs' in arg && arg.inputs) { + arg.inputs.forEach(processArg); + } + if (!('name' in arg)) return; + + const initialArg = initialArgs.find((a) => a.name === arg.name); + const initialArgValue = + initialArg?.value.type === 'str' + ? initialArg?.value.text + : initialArg?.value.type === 'bool' + ? initialArg.value.value + : undefined; + const value = initialArgValue ?? arg.defaultValue; + if (value != null) { + initial[arg.name] = value; + } + }; + + templateFunction.args.forEach(processArg); + + return initial; +} diff --git a/src-web/components/core/Select.tsx b/src-web/components/core/Select.tsx index c80dd1ee..6bdc0f43 100644 --- a/src-web/components/core/Select.tsx +++ b/src-web/components/core/Select.tsx @@ -24,6 +24,7 @@ export interface SelectProps { size?: ButtonProps['size']; className?: string; disabled?: boolean; + filterable?: boolean; } export function Select({ @@ -40,6 +41,7 @@ export function Select({ onChange, className, defaultValue, + filterable, size = 'md', }: SelectProps) { const [focused, setFocused] = useState(false); @@ -64,7 +66,7 @@ export function Select({ - {type() === 'macos' ? ( + {type() === 'macos' && !filterable ? ( e.id + e.updatedAt).join(':'); // Some auth handlers like OAuth 2.0 show the current token after a successful request. To // handle that, we'll force the auth to re-fetch after each new response closes @@ -41,6 +43,7 @@ export function useTemplateFunctionConfig( responseKey, workspaceId, environmentId, + environmentsKey, ], placeholderData: (prev) => prev, // Keep previous data on refetch queryFn: async () => { diff --git a/src-web/hooks/useTemplateFunctions.ts b/src-web/hooks/useTemplateFunctions.ts index a8ae4589..319621ca 100644 --- a/src-web/hooks/useTemplateFunctions.ts +++ b/src-web/hooks/useTemplateFunctions.ts @@ -20,27 +20,18 @@ export function useTemplateFunctionCompletionOptions( if (!enabled) { return []; } - return ( - templateFunctions.map((fn) => { - const NUM_ARGS = 2; - const argsWithName = fn.args.filter((a) => 'name' in a); - const shortArgs = - argsWithName - .slice(0, NUM_ARGS) - .map((a) => a.name) - .join(', ') + (fn.args.length > NUM_ARGS ? ', …' : ''); - return { - name: fn.name, - aliases: fn.aliases, - type: 'function', - description: fn.description, - args: argsWithName.map((a) => ({ name: a.name })), - value: null, - label: `${fn.name}(${shortArgs})`, - onClick: (rawTag: string, startPos: number) => onClick(fn, rawTag, startPos), - }; - }) ?? [] - ); + return templateFunctions.map((fn) => { + const argsLabel = fn.args.length > 0 ? '…' : ''; + const fn2: TwigCompletionOption = { + type: 'function', + onClick: (rawTag: string, startPos: number) => onClick(fn, rawTag, startPos), + label: `${fn.name}(${argsLabel})`, + invalid: false, + value: null, + ...fn, + }; + return fn2; + }); }, [enabled, onClick, templateFunctions]); }