diff --git a/package-lock.json b/package-lock.json index 8884c632..93c61994 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,7 +52,7 @@ "prettier-eslint": "^15.0.1", "ts-node": "^10.9.2", "tsc": "^2.0.4", - "tsup": "^8.0.1", + "tsup": "^8.5.1", "tsx": "^4.19.1", "typedoc": "^0.25.13", "typescript": "^5.4.5", @@ -234,9 +234,9 @@ } }, "node_modules/@commitlint/config-validator/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { @@ -1584,9 +1584,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.5.tgz", - "integrity": "sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", "cpu": [ "arm" ], @@ -1598,9 +1598,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.5.tgz", - "integrity": "sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", "cpu": [ "arm64" ], @@ -1612,9 +1612,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.5.tgz", - "integrity": "sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", "cpu": [ "arm64" ], @@ -1626,9 +1626,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.5.tgz", - "integrity": "sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", "cpu": [ "x64" ], @@ -1640,9 +1640,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.5.tgz", - "integrity": "sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", "cpu": [ "arm64" ], @@ -1654,9 +1654,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.5.tgz", - "integrity": "sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", "cpu": [ "x64" ], @@ -1668,9 +1668,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.5.tgz", - "integrity": "sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", "cpu": [ "arm" ], @@ -1682,9 +1682,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.5.tgz", - "integrity": "sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", "cpu": [ "arm" ], @@ -1696,9 +1696,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.5.tgz", - "integrity": "sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", "cpu": [ "arm64" ], @@ -1710,9 +1710,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.5.tgz", - "integrity": "sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", "cpu": [ "arm64" ], @@ -1724,9 +1724,23 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.5.tgz", - "integrity": "sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", "cpu": [ "loong64" ], @@ -1738,9 +1752,23 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.5.tgz", - "integrity": "sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", "cpu": [ "ppc64" ], @@ -1752,9 +1780,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.5.tgz", - "integrity": "sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", "cpu": [ "riscv64" ], @@ -1766,9 +1794,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.5.tgz", - "integrity": "sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", "cpu": [ "riscv64" ], @@ -1780,9 +1808,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.5.tgz", - "integrity": "sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", "cpu": [ "s390x" ], @@ -1806,9 +1834,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.5.tgz", - "integrity": "sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", "cpu": [ "x64" ], @@ -1819,10 +1847,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.5.tgz", - "integrity": "sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", "cpu": [ "arm64" ], @@ -1834,9 +1876,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.5.tgz", - "integrity": "sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", "cpu": [ "arm64" ], @@ -1848,9 +1890,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.5.tgz", - "integrity": "sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", "cpu": [ "ia32" ], @@ -1862,9 +1904,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.5.tgz", - "integrity": "sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", "cpu": [ "x64" ], @@ -1876,9 +1918,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.5.tgz", - "integrity": "sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", "cpu": [ "x64" ], @@ -2301,12 +2343,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -2474,12 +2517,13 @@ } }, "node_modules/@typescript-eslint/utils/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -2699,10 +2743,11 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", + "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -3624,10 +3669,11 @@ } }, "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -3669,9 +3715,10 @@ "dev": true }, "node_modules/dompurify": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.4.tgz", - "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", + "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", + "license": "(MPL-2.0 OR Apache-2.0)", "optionalDependencies": { "@types/trusted-types": "^2.0.7" } @@ -4445,9 +4492,9 @@ } }, "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "dev": true, "license": "ISC" }, @@ -5851,10 +5898,11 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "dev": true, + "license": "MIT" }, "node_modules/lodash-es": { "version": "4.17.23", @@ -6180,10 +6228,11 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -7115,9 +7164,9 @@ } }, "node_modules/rollup": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.5.tgz", - "integrity": "sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", "dependencies": { @@ -7131,35 +7180,38 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.52.5", - "@rollup/rollup-android-arm64": "4.52.5", - "@rollup/rollup-darwin-arm64": "4.52.5", - "@rollup/rollup-darwin-x64": "4.52.5", - "@rollup/rollup-freebsd-arm64": "4.52.5", - "@rollup/rollup-freebsd-x64": "4.52.5", - "@rollup/rollup-linux-arm-gnueabihf": "4.52.5", - "@rollup/rollup-linux-arm-musleabihf": "4.52.5", - "@rollup/rollup-linux-arm64-gnu": "4.52.5", - "@rollup/rollup-linux-arm64-musl": "4.52.5", - "@rollup/rollup-linux-loong64-gnu": "4.52.5", - "@rollup/rollup-linux-ppc64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-gnu": "4.52.5", - "@rollup/rollup-linux-riscv64-musl": "4.52.5", - "@rollup/rollup-linux-s390x-gnu": "4.52.5", - "@rollup/rollup-linux-x64-gnu": "4.52.5", - "@rollup/rollup-linux-x64-musl": "4.52.5", - "@rollup/rollup-openharmony-arm64": "4.52.5", - "@rollup/rollup-win32-arm64-msvc": "4.52.5", - "@rollup/rollup-win32-ia32-msvc": "4.52.5", - "@rollup/rollup-win32-x64-gnu": "4.52.5", - "@rollup/rollup-win32-x64-msvc": "4.52.5", + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", "fsevents": "~2.3.2" } }, "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.52.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.5.tgz", - "integrity": "sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==", + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", "cpu": [ "x64" ], @@ -7773,12 +7825,13 @@ } }, "node_modules/sucrase/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -7863,12 +7916,13 @@ } }, "node_modules/test-exclude/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -8436,12 +8490,13 @@ } }, "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -8634,12 +8689,13 @@ } }, "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" diff --git a/package.json b/package.json index 585a1cb9..2fd0bf34 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "test:watch": "vitest", "test:once": "vitest run", "test:coverage": "vitest --coverage", - "dev": "NODE_OPTIONS='--max-old-space-size=16384' tsup --watch", + "dev": "NODE_OPTIONS='--max-old-space-size=16384' tsup --watch --config tsup.config.dev.js", "prepare": "husky", "lint": "eslint src", "lint:fix": "eslint --fix", @@ -73,7 +73,7 @@ "prettier-eslint": "^15.0.1", "ts-node": "^10.9.2", "tsc": "^2.0.4", - "tsup": "^8.0.1", + "tsup": "^8.5.1", "tsx": "^4.19.1", "typedoc": "^0.25.13", "typescript": "^5.4.5", diff --git a/src/cslp/__test__/cslpdata.test.ts b/src/cslp/__test__/cslpdata.test.ts index 53905805..b297bbd5 100644 --- a/src/cslp/__test__/cslpdata.test.ts +++ b/src/cslp/__test__/cslpdata.test.ts @@ -1,4 +1,124 @@ -import { extractDetailsFromCslp } from "../cslpdata"; +import { extractDetailsFromCslp, isValidCslp } from "../cslpdata"; + +describe("isValidCslp", () => { + describe("valid cases", () => { + test("should return true for valid v1 format with 3 parts", () => { + expect( + isValidCslp("content_type_uid.entry_uid.locale") + ).toBeTruthy(); + }); + + test("should return true for valid v1 format with field path", () => { + expect( + isValidCslp("content_type_uid.entry_uid.locale.field_path") + ).toBeTruthy(); + }); + + test("should return true for valid v2 format with 3 parts", () => { + expect( + isValidCslp("v2:content_type_uid.entry_uid_variant_uid.locale") + ).toBeTruthy(); + }); + + test("should return true for valid v2 format with field path", () => { + expect( + isValidCslp( + "v2:content_type_uid.entry_uid_variant_uid.locale.field_path" + ) + ).toBeTruthy(); + }); + }); + + describe("invalid cases", () => { + test("should return false for null", () => { + expect(isValidCslp(null)).toBeFalsy(); + }); + + test("should return false for undefined", () => { + expect(isValidCslp(undefined)).toBeFalsy(); + }); + + test("should return false for empty string", () => { + expect(isValidCslp("")).toBeFalsy(); + }); + + test("should return false for string with less than 3 parts", () => { + expect(isValidCslp("invalid")).toBeFalsy(); + }); + + test("should return false for string with only 2 parts", () => { + expect(isValidCslp("a.b")).toBeFalsy(); + }); + + test("should return false for v2 prefix with no data", () => { + expect(isValidCslp("v2:")).toBeFalsy(); + }); + + test("should return false for v2 prefix with only 2 parts", () => { + expect(isValidCslp("v2:a.b")).toBeFalsy(); + }); + + test("should return false for v2 format where entry_uid_variant_uid has no underscore", () => { + expect( + isValidCslp("v2:content_type_uid.entry.locale") + ).toBeFalsy(); + }); + + test("should return false for v2 format where entry_uid_variant_uid is missing variant_uid", () => { + expect( + isValidCslp("v2:content_type_uid.entry_.locale") + ).toBeFalsy(); + }); + + test("should return false for v2 format where entry_uid_variant_uid is missing entry_uid", () => { + expect( + isValidCslp("v2:content_type_uid._variant_uid.locale") + ).toBeFalsy(); + }); + + test("should return false for v2 format with empty parts", () => { + expect(isValidCslp("v2:..locale")).toBeFalsy(); + }); + + test("should return false for v2 format with empty content_type_uid", () => { + expect(isValidCslp("v2:.entry_uid_variant_uid.locale")).toBeFalsy(); + }); + + test("should return false for v2 format with empty locale", () => { + expect( + isValidCslp("v2:content_type_uid.entry_uid_variant_uid.") + ).toBeFalsy(); + }); + + test("should return false for v1 format with empty parts", () => { + expect(isValidCslp("..locale")).toBeFalsy(); + }); + + test("should return false for v1 format with empty content_type_uid", () => { + expect(isValidCslp(".entry_uid.locale")).toBeFalsy(); + }); + + test("should return false for v1 format with empty entry_uid", () => { + expect(isValidCslp("content_type_uid..locale")).toBeFalsy(); + }); + + test("should return false for whitespace-only string", () => { + expect(isValidCslp(" ")).toBeFalsy(); + }); + + test("should return false for tab and newline whitespace", () => { + expect(isValidCslp("\t\n")).toBeFalsy(); + }); + + test("should return false for string with only dots", () => { + expect(isValidCslp("...")).toBeFalsy(); + }); + + test("should return false for string with only two dots", () => { + expect(isValidCslp("..")).toBeFalsy(); + }); + }); +}); describe("extractDetailsFromCslp", () => { test("should extract details from a CSLP value string with nested multiple field", () => { diff --git a/src/cslp/cslpdata.ts b/src/cslp/cslpdata.ts index 90f3fb65..661aed61 100644 --- a/src/cslp/cslpdata.ts +++ b/src/cslp/cslpdata.ts @@ -8,6 +8,76 @@ import Config from "../configManager/configManager"; import { DeepSignal } from "deepsignal"; import { cslpTagStyles } from "../livePreview/editButton/editButton.style"; +/** + * Validates that the required CSLP parts (content_type_uid, entry_uid/entry_uid_variant_uid, locale) are non-empty. + * @param parts The array of parts from splitting the CSLP string by "." + * @returns `true` if all required parts (first 3) are non-empty, `false` otherwise. + */ +function areRequiredPartsNonEmpty(parts: string[]): boolean { + // Check that we have at least 3 parts + if (parts.length < 3) { + return false; + } + // Verify that content_type_uid (parts[0]), entry_uid/entry_uid_variant_uid (parts[1]), and locale (parts[2]) are all non-empty + return parts[0].length > 0 && parts[1].length > 0 && parts[2].length > 0; +} + +/** + * Validates if a CSLP value string is valid. + * + * Supports two formats: + * - **v1 format**: `content_type_uid.entry_uid.locale[.field_path]` (requires at least 3 parts) + * - **v2 format**: `v2:content_type_uid.entry_uid_variant_uid.locale[.field_path]` + * (requires at least 3 parts, entry_uid_variant_uid must contain underscore separating entry_uid and variant_uid) + * + * @param cslpValue The CSLP value string to validate (can be null or undefined). + * @returns Type predicate: `true` if the CSLP value is valid (narrows type to `string`), `false` otherwise. + * + * @example + * Valid v1 format + * isValidCslp("page.entry123.en-us") -> true + * isValidCslp("page.entry123.en-us.title") -> true + * + * Valid v2 format + * isValidCslp("v2:page.entry123_variant456.en-us") -> true + * isValidCslp("v2:page.entry123_variant456.en-us.title") -> true + * + * Invalid cases + * isValidCslp(null) -> false + * isValidCslp("invalid") -> false (less than 3 parts) + * isValidCslp("v2:page.entry123.en-us") -> false (missing underscore in entry_uid_variant_uid) + */ +export function isValidCslp( + cslpValue: string | null | undefined +): cslpValue is string { + // Return false for null, undefined, or empty string + if (!cslpValue) { + return false; + } + + // Check for v2 format (starts with "v2:") + if (cslpValue.startsWith("v2:")) { + const dataAfterPrefix = cslpValue.substring(3); // Remove "v2:" prefix + const parts = dataAfterPrefix.split("."); + // v2 format requires at least 3 parts: content_type_uid.entry_uid_variant_uid.locale + // Verify that content_type_uid, entry_uid_variant_uid, and locale are all non-empty + if (!areRequiredPartsNonEmpty(parts)) { + return false; + } + // Verify that entry_uid_variant_uid (second part) contains both entry_uid and variant_uid separated by at least one underscore + const entryUidVariantUid = parts[1]; + const entryVariantParts = entryUidVariantUid.split("_"); + // Check that we have at least 2 parts (entry_uid and variant_uid) and all parts are non-empty + return entryVariantParts.length >= 2 && entryVariantParts.every((part) => part.length > 0); + } + + // v1 format (default, no prefix) + const parts = cslpValue.split("."); + // v1 format requires at least 3 parts: content_type_uid.entry_uid.locale + // Verify that content_type_uid, entry_uid, and locale are all non-empty + return areRequiredPartsNonEmpty(parts); +} + /** * Extracts details from a CSLP value string. * @param cslpValue The CSLP value string to extract details from. @@ -163,7 +233,7 @@ export function addCslpOutline( const cslpTag = element.getAttribute("data-cslp"); - if (trigger && cslpTag) { + if (trigger && isValidCslp(cslpTag)) { if (elements.highlightedElement) elements.highlightedElement.classList.remove( cslpTagStyles()["cslp-edit-mode"] diff --git a/src/livePreview/editButton/editButton.ts b/src/livePreview/editButton/editButton.ts index df88fc7d..7d84fe5c 100644 --- a/src/livePreview/editButton/editButton.ts +++ b/src/livePreview/editButton/editButton.ts @@ -1,7 +1,7 @@ import { effect } from "@preact/signals"; import { inIframe, isOpeningInNewTab } from "../../common/inIframe"; import Config from "../../configManager/configManager"; -import { addCslpOutline, extractDetailsFromCslp } from "../../cslp"; +import { addCslpOutline, extractDetailsFromCslp, isValidCslp } from "../../cslp"; import { cslpTagStyles } from "./editButton.style"; import { PublicLogger } from "../../logger/logger"; import { @@ -439,7 +439,7 @@ export class LivePreviewEditButton { const cslpTag = this.tooltip.getAttribute("current-data-cslp"); - if (cslpTag) { + if (isValidCslp(cslpTag)) { const { content_type_uid, entry_uid, diff --git a/src/timeline/compare/compare.ts b/src/timeline/compare/compare.ts index abdac01d..cbd5db3d 100644 --- a/src/timeline/compare/compare.ts +++ b/src/timeline/compare/compare.ts @@ -1,6 +1,7 @@ import timelinePostMessage from "../timelinePostMessage/timelinePostMessage"; import { timelinePostMessageEvents } from "../timelinePostMessage/timelinePostMessage.constant"; import { compareGlobalStyles } from "./compare.style"; +import { isValidCslp } from "../../cslp/cslpdata"; const voidElements = new Set([ "area", @@ -64,7 +65,8 @@ export function handleWebCompare() { ); const map: Record = {}; for (const element of elements) { - const cslp = element.getAttribute("data-cslp")!; + const cslp = element.getAttribute("data-cslp"); + if (!isValidCslp(cslp)) continue; if ( element.hasAttributes() && voidElements.has(element.tagName.toLowerCase()) @@ -101,8 +103,8 @@ export function handleWebCompare() { document.querySelectorAll(LEAF_CSLP_SELECTOR) ); for (const element of elements) { - const path = element.getAttribute("data-cslp")!; - if (!diff[path]) continue; + const path = element.getAttribute("data-cslp"); + if (!isValidCslp(path) || !diff[path]) continue; if (voidElements.has(element.tagName.toLowerCase())) { element.classList.add(`cs-compare__void--${operation}`); diff --git a/src/visualBuilder/components/__test__/startEditingButton.test.tsx b/src/visualBuilder/components/__test__/startEditingButton.test.tsx index b4aa7122..8a5a943f 100644 --- a/src/visualBuilder/components/__test__/startEditingButton.test.tsx +++ b/src/visualBuilder/components/__test__/startEditingButton.test.tsx @@ -1,5 +1,7 @@ import { render, fireEvent, screen } from "@testing-library/preact"; -import StartEditingButtonComponent, { getEditButtonPosition } from "../startEditingButton"; +import StartEditingButtonComponent, { + getEditButtonPosition, +} from "../startEditingButton"; import Config from "../../../configManager/configManager"; import { asyncRender } from "../../../__test__/utils"; @@ -7,7 +9,7 @@ describe("StartEditingButtonComponent", () => { let visualBuilderContainer: HTMLDivElement; beforeEach(() => { - document.getElementsByTagName('html')[0].innerHTML = ''; + document.getElementsByTagName("html")[0].innerHTML = ""; Config.reset(); Config.set("stackDetails.apiKey", "bltapikey"); Config.set("stackDetails.environment", "bltenvironment"); @@ -38,103 +40,120 @@ describe("StartEditingButtonComponent", () => { }); test("should update the href when clicked", async () => { - const { getByTestId } = await asyncRender(); + const { getByTestId } = await asyncRender( + + ); const button = getByTestId("vcms-start-editing-btn"); expect(button?.getAttribute("href")).toBe( - "https://app.contentstack.com/#!/stack/bltapikey/visual-builder?branch=main&environment=bltenvironment&target-url=http%3A%2F%2Flocalhost%3A3000%2F&locale=en-us" + "https://app.contentstack.com/#!/stack/bltapikey/visual-editor?branch=main&environment=bltenvironment&target-url=http%3A%2F%2Flocalhost%3A3000%2F&locale=en-us" ); }); test("should not render when enable is false", async () => { Config.set("editInVisualBuilderButton.enable", false); - const { container } = await asyncRender(); + const { container } = await asyncRender( + + ); expect(container).toBeEmptyDOMElement(); }); test("should render when enable is true", async () => { Config.set("editInVisualBuilderButton.enable", true); - const { getByTestId } = await asyncRender(); + const { getByTestId } = await asyncRender( + + ); const button = getByTestId("vcms-start-editing-btn"); expect(button).toBeInTheDocument(); }); - test.each([ - 'bottom-right', - 'bottom-left', - 'top-left', - 'top-right' - ])('should return valid position %s', (position) => { - expect(getEditButtonPosition(position)).toBe(position); - }); + test.each(["bottom-right", "bottom-left", "top-left", "top-right"])( + "should return valid position %s", + (position) => { + expect(getEditButtonPosition(position)).toBe(position); + } + ); test.each([ - 'invalid-position', - 'center', - '', + "invalid-position", + "center", + "", undefined, null, 123, {}, [], false, - ])('should return bottom-right for invalid input: %s', (invalidPosition) => { - expect(getEditButtonPosition(invalidPosition)).toBe('bottom-right'); - }); - + ])( + "should return bottom-right for invalid input: %s", + (invalidPosition) => { + expect(getEditButtonPosition(invalidPosition)).toBe("bottom-right"); + } + ); + test("should render with default values when editInVisualBuilderButton config is missing", async () => { Config.reset(); Config.set("stackDetails.apiKey", "bltapikey"); Config.set("stackDetails.environment", "bltenvironment"); - const { getByTestId } = await asyncRender(); + const { getByTestId } = await asyncRender( + + ); const button = getByTestId("vcms-start-editing-btn"); - - expect(Config.get().editInVisualBuilderButton.position).toBe("bottom-right") + + expect(Config.get().editInVisualBuilderButton.position).toBe( + "bottom-right" + ); expect(button).toBeInTheDocument(); }); test("should update href with current URL when mouse enters button", async () => { - Object.defineProperty(window, 'location', { - value: new URL('http://localhost:3000'), + Object.defineProperty(window, "location", { + value: new URL("http://localhost:3000"), }); - - const { getByTestId } = await asyncRender(); + + const { getByTestId } = await asyncRender( + + ); const button = getByTestId("vcms-start-editing-btn"); const initialHref = button.getAttribute("href"); - - Object.defineProperty(window, 'location', { - value: new URL('http://localhost:3000/about'), - writable: true + + Object.defineProperty(window, "location", { + value: new URL("http://localhost:3000/about"), + writable: true, }); fireEvent.mouseEnter(button); - + const updatedHref = button.getAttribute("href"); expect(updatedHref).not.toBe(initialHref); - expect(updatedHref).toContain(encodeURIComponent("http://localhost:3000/about")); + expect(updatedHref).toContain( + encodeURIComponent("http://localhost:3000/about") + ); }); test("should update href with current URL when button is focused", async () => { - Object.defineProperty(window, 'location', { - value: new URL('http://localhost:3000'), + Object.defineProperty(window, "location", { + value: new URL("http://localhost:3000"), }); - - const { getByTestId } = await asyncRender(); + + const { getByTestId } = await asyncRender( + + ); const button = getByTestId("vcms-start-editing-btn"); const initialHref = button.getAttribute("href"); - - Object.defineProperty(window, 'location', { - value: new URL('http://localhost:3000/contact'), - writable: true + + Object.defineProperty(window, "location", { + value: new URL("http://localhost:3000/contact"), + writable: true, }); fireEvent.focus(button); - + const updatedHref = button.getAttribute("href"); expect(updatedHref).not.toBe(initialHref); - expect(updatedHref).toContain(encodeURIComponent("http://localhost:3000/contact")); + expect(updatedHref).toContain( + encodeURIComponent("http://localhost:3000/contact") + ); }); - - }); diff --git a/src/visualBuilder/components/fieldLabelWrapper.tsx b/src/visualBuilder/components/fieldLabelWrapper.tsx index 2e3d0d6e..af2ed986 100644 --- a/src/visualBuilder/components/fieldLabelWrapper.tsx +++ b/src/visualBuilder/components/fieldLabelWrapper.tsx @@ -1,6 +1,6 @@ import classNames from "classnames"; import React, { useEffect, useState } from "preact/compat"; -import { extractDetailsFromCslp } from "../../cslp"; +import { extractDetailsFromCslp, isValidCslp } from "../../cslp"; import { CslpData } from "../../cslp/types/cslp.types"; import { VisualBuilderCslpEventDetails } from "../types/visualBuilder.types"; import { FieldSchemaMap } from "../utils/fieldSchemaMap"; @@ -144,7 +144,7 @@ function FieldLabelWrapperComponent( const domAncestor = eventDetails.editableElement.closest(`[data-cslp]:not([data-cslp^="${props.fieldMetadata.content_type_uid}"])`); if(domAncestor) { const domAncestorCslp = domAncestor.getAttribute("data-cslp"); - if (domAncestorCslp) { + if (isValidCslp(domAncestorCslp)) { const domAncestorDetails = extractDetailsFromCslp(domAncestorCslp); const domAncestorContentTypeUid = domAncestorDetails.content_type_uid; const domAncestorContentParent = referenceData?.find(data => data.contentTypeUid === domAncestorContentTypeUid); diff --git a/src/visualBuilder/eventManager/__test__/useRevalidateFieldDataPostMessageEvent.test.ts b/src/visualBuilder/eventManager/__test__/useRevalidateFieldDataPostMessageEvent.test.ts index 0d41da73..964be326 100644 --- a/src/visualBuilder/eventManager/__test__/useRevalidateFieldDataPostMessageEvent.test.ts +++ b/src/visualBuilder/eventManager/__test__/useRevalidateFieldDataPostMessageEvent.test.ts @@ -2,7 +2,7 @@ import { vi, describe, it, expect, beforeEach, afterEach } from "vitest"; import { VisualBuilder } from "../.."; import { FieldSchemaMap } from "../../utils/fieldSchemaMap"; import { handleRevalidateFieldData } from "../useRevalidateFieldDataPostMessageEvent"; - +import * as cslpdata from "../../../cslp"; // Mock dependencies vi.mock("../../utils/fieldSchemaMap", () => ({ FieldSchemaMap: { @@ -11,9 +11,7 @@ vi.mock("../../utils/fieldSchemaMap", () => ({ }, })); -vi.mock("../../../cslp", () => ({ - extractDetailsFromCslp: vi.fn(), -})); +vi.spyOn(cslpdata, "extractDetailsFromCslp"); vi.mock("../../generators/generateOverlay", () => ({ hideFocusOverlay: vi.fn(), diff --git a/src/visualBuilder/eventManager/__test__/useVariantsPostMessageEvent.spec.ts b/src/visualBuilder/eventManager/__test__/useVariantsPostMessageEvent.spec.ts index f2528c65..78b25bb3 100644 --- a/src/visualBuilder/eventManager/__test__/useVariantsPostMessageEvent.spec.ts +++ b/src/visualBuilder/eventManager/__test__/useVariantsPostMessageEvent.spec.ts @@ -153,6 +153,9 @@ describe("useVariantFieldsPostMessageEvent", () => { // Reset mocks vi.clearAllMocks(); + + // Mock isValidCslp to return true for test data (after clearAllMocks) + vi.spyOn(cslpdata, "isValidCslp").mockReturnValue(true); }); afterEach(() => { @@ -362,6 +365,9 @@ describe("addVariantFieldClass", () => { // Reset mocks vi.clearAllMocks(); + + // Mock isValidCslp to return true for test data + vi.spyOn(cslpdata, "isValidCslp").mockReturnValue(true); }); afterEach(() => { @@ -423,6 +429,7 @@ describe("addVariantFieldClass", () => { variant: cslpValue.split(":")[1] } }); + const variantUid = "variant-456"; const variantOrder = ["variant-123", "variant-456"]; VisualBuilder.VisualBuilderGlobalState.value.variantOrder = variantOrder; diff --git a/src/visualBuilder/eventManager/useRecalculateVariantDataCSLPValues.ts b/src/visualBuilder/eventManager/useRecalculateVariantDataCSLPValues.ts index 54142d82..7c4f1ba2 100644 --- a/src/visualBuilder/eventManager/useRecalculateVariantDataCSLPValues.ts +++ b/src/visualBuilder/eventManager/useRecalculateVariantDataCSLPValues.ts @@ -3,6 +3,7 @@ import livePreviewPostMessage from "../../livePreview/eventManager/livePreviewEv import { LIVE_PREVIEW_POST_MESSAGE_EVENTS } from "../../livePreview/eventManager/livePreviewEventManager.constant"; import { DATA_CSLP_ATTR_SELECTOR } from "../utils/constants"; import { visualBuilderStyles } from "../visualBuilder.style"; +import { isValidCslp } from "../../cslp/cslpdata"; import { setHighlightVariantFields } from "./useVariantsPostMessageEvent"; const VARIANT_UPDATE_DELAY_MS: Readonly = 8000; @@ -37,7 +38,7 @@ export function updateVariantClasses(): void { dataCslp: string, observer?: MutationObserver ) => { - if (!dataCslp) return; + if (!isValidCslp(dataCslp)) return; if ( dataCslp.startsWith("v2:") && @@ -84,7 +85,7 @@ export function updateVariantClasses(): void { const addElementClasses = (element: HTMLElement) => { const dataCslp = element.getAttribute(DATA_CSLP_ATTR_SELECTOR); - if (!dataCslp) { + if (!isValidCslp(dataCslp)) { //recursive call for child nodes element.childNodes.forEach((child) => { if (child instanceof HTMLElement) { diff --git a/src/visualBuilder/eventManager/useRevalidateFieldDataPostMessageEvent.ts b/src/visualBuilder/eventManager/useRevalidateFieldDataPostMessageEvent.ts index d984333a..339b8007 100644 --- a/src/visualBuilder/eventManager/useRevalidateFieldDataPostMessageEvent.ts +++ b/src/visualBuilder/eventManager/useRevalidateFieldDataPostMessageEvent.ts @@ -1,5 +1,5 @@ import { VisualBuilder } from ".."; -import { extractDetailsFromCslp } from "../../cslp"; +import { extractDetailsFromCslp, isValidCslp } from "../../cslp"; import { FieldSchemaMap } from "../utils/fieldSchemaMap"; import { hideFocusOverlay } from "../generators/generateOverlay"; import { handleBuilderInteraction } from "../listeners/mouseClick"; @@ -32,7 +32,7 @@ export async function handleRevalidateFieldData(): Promise { if (targetElement) { const cslp = targetElement.getAttribute("data-cslp"); - if (cslp) { + if (isValidCslp(cslp)) { const fieldMetadata = extractDetailsFromCslp(cslp); // Try to revalidate specific field schema and data @@ -51,7 +51,7 @@ export async function handleRevalidateFieldData(): Promise { window.location.reload(); } finally { // Step 3: Refocus the element if we had one focused before - if (shouldRefocus && elementCslp) { + if (shouldRefocus && isValidCslp(elementCslp)) { await refocusElement(elementCslp, elementCslpUniqueId); } } diff --git a/src/visualBuilder/eventManager/useVariantsPostMessageEvent.ts b/src/visualBuilder/eventManager/useVariantsPostMessageEvent.ts index 382a6976..ba02c539 100644 --- a/src/visualBuilder/eventManager/useVariantsPostMessageEvent.ts +++ b/src/visualBuilder/eventManager/useVariantsPostMessageEvent.ts @@ -5,7 +5,7 @@ import { VisualBuilderPostMessageEvents } from "../utils/types/postMessage.types import { FieldSchemaMap } from "../utils/fieldSchemaMap"; import { updateVariantClasses } from "./useRecalculateVariantDataCSLPValues"; import { debounce } from "lodash-es"; -import { extractDetailsFromCslp } from "../../cslp/cslpdata"; +import { extractDetailsFromCslp, isValidCslp } from "../../cslp/cslpdata"; interface VariantFieldsEvent { data: { @@ -61,7 +61,7 @@ export function addVariantFieldClass( const elements = document.querySelectorAll(`[data-cslp]`); elements.forEach((element) => { const dataCslp = element.getAttribute("data-cslp"); - if (!dataCslp) return; + if (!isValidCslp(dataCslp)) return; if (dataCslp?.includes(variant_uid)) { element.classList.add("visual-builder__variant-field"); diff --git a/src/visualBuilder/generators/__test__/generateOverlay.test.ts b/src/visualBuilder/generators/__test__/generateOverlay.test.ts index 02de3274..169ef54f 100644 --- a/src/visualBuilder/generators/__test__/generateOverlay.test.ts +++ b/src/visualBuilder/generators/__test__/generateOverlay.test.ts @@ -4,7 +4,7 @@ import { VisualBuilder } from "../.."; import { VisualBuilderPostMessageEvents } from "../../utils/types/postMessage.types"; import visualBuilderPostMessage from "../../utils/visualBuilderPostMessage"; import { FieldSchemaMap } from "../../utils/fieldSchemaMap"; -import { extractDetailsFromCslp } from "../../../cslp/cslpdata"; +import * as cslpdata from "../../../cslp/cslpdata"; vi.mock("../../utils/visualBuilderPostMessage", () => ({ default: { @@ -21,9 +21,7 @@ vi.mock("../../utils/fieldSchemaMap", () => ({ }, })); -vi.mock("../../../cslp/cslpdata", () => ({ - extractDetailsFromCslp: vi.fn(), -})); +vi.spyOn(cslpdata, "extractDetailsFromCslp"); describe("sendFieldEvent", () => { let previousSelectedEditableDOM: HTMLElement; @@ -55,7 +53,7 @@ describe("sendFieldEvent", () => { eventType: VisualBuilderPostMessageEvents.UPDATE_FIELD, }); - expect(extractDetailsFromCslp).not.toHaveBeenCalled(); + expect(cslpdata.extractDetailsFromCslp).not.toHaveBeenCalled(); expect(FieldSchemaMap.getFieldSchema).not.toHaveBeenCalled(); expect(visualBuilderPostMessage?.send).not.toHaveBeenCalled(); }); diff --git a/src/visualBuilder/generators/generateEmptyBlock.tsx b/src/visualBuilder/generators/generateEmptyBlock.tsx index 8797230a..f3ef81f8 100644 --- a/src/visualBuilder/generators/generateEmptyBlock.tsx +++ b/src/visualBuilder/generators/generateEmptyBlock.tsx @@ -1,6 +1,7 @@ import { hydrate } from "preact"; +import React from "preact/compat"; import { EmptyBlock } from "../components/emptyBlock"; -import { extractDetailsFromCslp } from "../../cslp"; +import { extractDetailsFromCslp, isValidCslp } from "../../cslp"; import { FieldSchemaMap } from "../utils/fieldSchemaMap"; export async function generateEmptyBlocks( @@ -8,7 +9,7 @@ export async function generateEmptyBlocks( ): Promise { for (const emptyBlockParent of emptyBlockParents) { const cslpData = emptyBlockParent.getAttribute("data-cslp"); - if (!cslpData) { + if (!isValidCslp(cslpData)) { return; } const fieldMetadata = extractDetailsFromCslp(cslpData); diff --git a/src/visualBuilder/generators/generateHighlightedComment.tsx b/src/visualBuilder/generators/generateHighlightedComment.tsx index 324a12e4..7fa8c7c9 100644 --- a/src/visualBuilder/generators/generateHighlightedComment.tsx +++ b/src/visualBuilder/generators/generateHighlightedComment.tsx @@ -4,6 +4,7 @@ import HighlightedCommentIcon from "../components/HighlightedCommentIcon"; import { css } from "goober"; import React from "preact/compat"; import { IHighlightCommentData } from "../eventManager/useHighlightCommentIcon"; +import { isValidCslp } from "../../cslp"; /** * Inserts highlighted comment icons based on an array of paths. @@ -24,7 +25,7 @@ export function highlightCommentIconOnCanvas( const cslpValue = data?.fieldMetadata?.cslpValue; // Check if the cslpValue is already in the Object - if (!cslpValue || uniquePaths[cslpValue]) { + if (!isValidCslp(cslpValue) || uniquePaths[cslpValue]) { return; // Skip if the value is not unique } diff --git a/src/visualBuilder/generators/generateOverlay.tsx b/src/visualBuilder/generators/generateOverlay.tsx index 595cefff..abe99821 100644 --- a/src/visualBuilder/generators/generateOverlay.tsx +++ b/src/visualBuilder/generators/generateOverlay.tsx @@ -1,4 +1,4 @@ -import { extractDetailsFromCslp } from "../../cslp/cslpdata"; +import { extractDetailsFromCslp, isValidCslp } from "../../cslp/cslpdata"; import { cleanIndividualFieldResidual } from "../utils/handleIndividualFields"; import visualBuilderPostMessage from "../utils/visualBuilderPostMessage"; import { VisualBuilderPostMessageEvents } from "../utils/types/postMessage.types"; @@ -178,7 +178,7 @@ export function sendFieldEvent(options: ISendFieldEventParams): void { : actualEditedElement.textContent; const cslpData = previousSelectedEditableDOM.getAttribute("data-cslp"); - if (!cslpData) { + if (!isValidCslp(cslpData)) { return; } diff --git a/src/visualBuilder/index.ts b/src/visualBuilder/index.ts index 8e24ba8c..7040bba7 100644 --- a/src/visualBuilder/index.ts +++ b/src/visualBuilder/index.ts @@ -21,7 +21,7 @@ import { VisualBuilderPostMessageEvents } from "./utils/types/postMessage.types" import { setup } from "goober"; import { debounce, isEqual } from "lodash-es"; import { h } from "preact"; -import { extractDetailsFromCslp } from "../cslp"; +import { extractDetailsFromCslp, isValidCslp } from "../cslp"; import initUI from "./components"; import { useDraftFieldsPostMessageEvent } from "./eventManager/useDraftFieldsPostMessageEvent"; import { useHideFocusOverlayPostMessageEvent } from "./eventManager/useHideFocusOverlayPostMessageEvent"; @@ -180,7 +180,7 @@ export class VisualBuilder { const cslpData = editableElement && editableElement.getAttribute("data-cslp"); - if (!editableElement || !cslpData) { + if (!editableElement || !isValidCslp(cslpData)) { return; } diff --git a/src/visualBuilder/listeners/mouseClick.ts b/src/visualBuilder/listeners/mouseClick.ts index 76b2ca9e..c78bd820 100644 --- a/src/visualBuilder/listeners/mouseClick.ts +++ b/src/visualBuilder/listeners/mouseClick.ts @@ -7,6 +7,7 @@ import { getCsDataOfElement, getDOMEditStack, } from "../utils/getCsDataOfElement"; +import { isValidCslp } from "../../cslp"; import { appendFocusedToolbar } from "../generators/generateToolbar"; @@ -91,16 +92,19 @@ export async function handleBuilderInteraction( // assign a unique ID to each element which we can use to identify // them in updateFocussedState and other places where we // would have queried the element by data-cslp - const duplicates = document.querySelectorAll( - `[data-cslp="${eventTarget?.getAttribute("data-cslp")}"]` - ); - if (duplicates.length > 1) { - duplicates.forEach((ele) => { - if (!ele.hasAttribute("data-cslp-unique-id")) { - const uniqueId = `cslp-${uuidV4()}`; - ele.setAttribute("data-cslp-unique-id", uniqueId); - } - }); + const eventTargetCslp = eventTarget?.getAttribute("data-cslp"); + if (isValidCslp(eventTargetCslp)) { + const duplicates = document.querySelectorAll( + `[data-cslp="${eventTargetCslp}"]` + ); + if (duplicates.length > 1) { + duplicates.forEach((ele) => { + if (!ele.hasAttribute("data-cslp-unique-id")) { + const uniqueId = `cslp-${uuidV4()}`; + ele.setAttribute("data-cslp-unique-id", uniqueId); + } + }); + } } // if the target element is a studio-ui element, return diff --git a/src/visualBuilder/utils/__test__/generateStartEditingButton.test.ts b/src/visualBuilder/utils/__test__/generateStartEditingButton.test.ts index e652fffe..457a8159 100644 --- a/src/visualBuilder/utils/__test__/generateStartEditingButton.test.ts +++ b/src/visualBuilder/utils/__test__/generateStartEditingButton.test.ts @@ -39,7 +39,7 @@ describe("generateStartEditingButton", () => { button?.click(); expect(button?.getAttribute("href")).toBe( - "https://app.contentstack.com/#!/stack//visual-builder?branch=main&target-url=http%3A%2F%2Flocalhost%3A3000%2F&locale=en-us" + "https://app.contentstack.com/#!/stack//visual-editor?branch=main&target-url=http%3A%2F%2Flocalhost%3A3000%2F&locale=en-us" ); }); @@ -57,7 +57,7 @@ describe("generateStartEditingButton", () => { button?.click(); expect(button?.getAttribute("href")).toBe( - "https://app.contentstack.com/#!/stack//visual-builder?branch=main&target-url=http%3A%2F%2Flocalhost%3A3000%2F&locale=en-us" + "https://app.contentstack.com/#!/stack//visual-editor?branch=main&target-url=http%3A%2F%2Flocalhost%3A3000%2F&locale=en-us" ); }); }); diff --git a/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts b/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts index c09ec900..87e77321 100644 --- a/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts +++ b/src/visualBuilder/utils/__test__/getVisualBuilderRedirectionUrl.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect, vi } from 'vitest'; import getVisualBuilderRedirectionUrl from '../getVisualBuilderRedirectionUrl'; import Config from '../../../configManager/configManager'; -import { extractDetailsFromCslp } from '../../../cslp'; +import { extractDetailsFromCslp, isValidCslp } from '../../../cslp'; vi.mock('../../../configManager/configManager'); vi.mock('../../../cslp'); @@ -27,7 +27,7 @@ describe('getVisualBuilderRedirectionUrl', () => { }); const result = getVisualBuilderRedirectionUrl(); - expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=en-US'); + expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-editor?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=en-US'); }); it('should return the correct URL without branch and environment', () => { @@ -44,7 +44,7 @@ describe('getVisualBuilderRedirectionUrl', () => { }); const result = getVisualBuilderRedirectionUrl(); - expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-builder?target-url=https%3A%2F%2Fexample.com%2F&locale=en-US'); + expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-editor?target-url=https%3A%2F%2Fexample.com%2F&locale=en-US'); }); it('should use locale from data-cslp attribute if present', () => { @@ -61,10 +61,11 @@ describe('getVisualBuilderRedirectionUrl', () => { } }); + isValidCslp.mockReturnValue(true); extractDetailsFromCslp.mockReturnValue({ locale: 'fr-FR' }); const result = getVisualBuilderRedirectionUrl(); - expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=fr-FR'); + expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-editor?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=fr-FR'); }); it('should return the correct URL without locale', () => { @@ -82,7 +83,7 @@ describe('getVisualBuilderRedirectionUrl', () => { }); const result = getVisualBuilderRedirectionUrl(); - expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F'); + expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-editor?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F'); }); it('should ignore invalid data-cslp attribute and use locale from config', () => { @@ -99,9 +100,11 @@ describe('getVisualBuilderRedirectionUrl', () => { } }); + isValidCslp.mockReturnValue(false); + const result = getVisualBuilderRedirectionUrl(); // Should use locale from config when data-cslp attribute is invalid (empty or no value) - expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-builder?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=en-US'); + expect(result.toString()).toBe('https://app.example.com/#!/stack/12345/visual-editor?branch=main&environment=production&target-url=https%3A%2F%2Fexample.com%2F&locale=en-US'); // Should not call extractDetailsFromCslp for invalid cslp expect(extractDetailsFromCslp).not.toHaveBeenCalled(); }); diff --git a/src/visualBuilder/utils/getCsDataOfElement.ts b/src/visualBuilder/utils/getCsDataOfElement.ts index 7139a50f..a4d952dc 100644 --- a/src/visualBuilder/utils/getCsDataOfElement.ts +++ b/src/visualBuilder/utils/getCsDataOfElement.ts @@ -1,6 +1,6 @@ import { CslpData } from "../../cslp/types/cslp.types"; import { VisualBuilderCslpEventDetails } from "../types/visualBuilder.types"; -import { extractDetailsFromCslp } from "../../cslp/cslpdata"; +import { extractDetailsFromCslp, isValidCslp } from "../../cslp/cslpdata"; import { DATA_CSLP_ATTR_SELECTOR } from "./constants"; /** @@ -23,7 +23,7 @@ export function getCsDataOfElement( return; } const cslpData = editableElement.getAttribute("data-cslp"); - if (!cslpData) { + if (!isValidCslp(cslpData)) { return; } const fieldMetadata = extractDetailsFromCslp(cslpData); @@ -55,7 +55,7 @@ export function getDOMEditStack(ele: Element): CslpData[] { let curr: any = ele.closest(`[${DATA_CSLP_ATTR_SELECTOR}]`); while (curr) { const cslp = curr.getAttribute(DATA_CSLP_ATTR_SELECTOR); - if (!cslp) { + if (!isValidCslp(cslp)) { curr = curr.parentElement?.closest(`[${DATA_CSLP_ATTR_SELECTOR}]`); continue; } @@ -68,5 +68,5 @@ export function getDOMEditStack(ele: Element): CslpData[] { } curr = curr.parentElement?.closest(`[${DATA_CSLP_ATTR_SELECTOR}]`); } - return cslpSet.filter((cslp) => cslp).map((cslp) => extractDetailsFromCslp(cslp)); + return cslpSet.filter(isValidCslp).map((cslp) => extractDetailsFromCslp(cslp)); } diff --git a/src/visualBuilder/utils/getEntryIdentifiersInCurrentPage.ts b/src/visualBuilder/utils/getEntryIdentifiersInCurrentPage.ts index 243bc4a1..d3e74685 100644 --- a/src/visualBuilder/utils/getEntryIdentifiersInCurrentPage.ts +++ b/src/visualBuilder/utils/getEntryIdentifiersInCurrentPage.ts @@ -1,4 +1,4 @@ -import { extractDetailsFromCslp } from "../../cslp/cslpdata"; +import { extractDetailsFromCslp, isValidCslp } from "../../cslp/cslpdata"; type EntryIdentifiers = { entriesInCurrentPage: { @@ -15,7 +15,7 @@ export function getEntryIdentifiersInCurrentPage(): EntryIdentifiers { const uniqueEntriesMap = new Map(); elementsWithCslp.forEach((element) => { const cslpValue = element.getAttribute("data-cslp"); - if (!cslpValue) return; + if (!isValidCslp(cslpValue)) return; const cslpData = extractDetailsFromCslp(cslpValue); uniqueEntriesMap.set(cslpData.entry_uid, { diff --git a/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts b/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts index 02e4659b..70a76b19 100644 --- a/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts +++ b/src/visualBuilder/utils/getVisualBuilderRedirectionUrl.ts @@ -1,5 +1,5 @@ import Config from "../../configManager/configManager"; -import { extractDetailsFromCslp } from "../../cslp"; +import { extractDetailsFromCslp, isValidCslp } from "../../cslp"; /** * Returns the redirection URL for the Visual builder. @@ -26,7 +26,7 @@ export default function getVisualBuilderRedirectionUrl(): URL { if (elementWithDataCslp) { const cslpData = elementWithDataCslp.getAttribute("data-cslp"); - if (cslpData) { + if (isValidCslp(cslpData)) { const { locale: cslpLocale } = extractDetailsFromCslp(cslpData); localeToUse = cslpLocale; } @@ -37,7 +37,7 @@ export default function getVisualBuilderRedirectionUrl(): URL { } const completeURL = new URL( - `/#!/stack/${apiKey}/visual-builder?${searchParams.toString()}`, + `/#!/stack/${apiKey}/visual-editor?${searchParams.toString()}`, appUrl ); return completeURL; diff --git a/src/visualBuilder/utils/updateFocussedState.ts b/src/visualBuilder/utils/updateFocussedState.ts index 989560f2..295a5683 100644 --- a/src/visualBuilder/utils/updateFocussedState.ts +++ b/src/visualBuilder/utils/updateFocussedState.ts @@ -1,5 +1,5 @@ import { VisualBuilder } from ".."; -import { extractDetailsFromCslp } from "../../cslp"; +import { extractDetailsFromCslp, isValidCslp } from "../../cslp"; import { getAddInstanceButtons } from "../generators/generateAddInstanceButtons"; import { addFocusOverlay, @@ -136,7 +136,7 @@ export async function updateFocussedState({ } const cslp = editableElement?.getAttribute("data-cslp") || ""; - if (!cslp) { + if (!isValidCslp(cslp)) { return; } const fieldMetadata = extractDetailsFromCslp(cslp); diff --git a/tsup.config.dev.js b/tsup.config.dev.js new file mode 100644 index 00000000..5de64b78 --- /dev/null +++ b/tsup.config.dev.js @@ -0,0 +1,21 @@ +import { defineConfig } from 'tsup' +import { modernConfig } from './tsup.config.js' + +/** + * Dev config: Optimized for faster development builds + * - Skips type generation (dts: false) for faster compilation + */ +export default defineConfig([ + { + ...modernConfig({ + entry: [ + "src/**/*.ts", + "src/**/*.tsx", + "!src/**/__test__", + "!**/*.test.ts", + "!**/*.test.tsx", + ], + }), + dts: false + }, +]) diff --git a/tsup.config.js b/tsup.config.js index 70fe3c6f..49a5f244 100644 --- a/tsup.config.js +++ b/tsup.config.js @@ -11,7 +11,7 @@ export default defineConfig([ }), ]) -function modernConfig(opts) { +export function modernConfig(opts) { return { entry: opts.entry, define: {