diff --git a/package-lock.json b/package-lock.json index 81359a0fb5..6f8f906fec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,20 @@ "xml-js": "^1.6.11" } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@asamuzakjp/css-color": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", @@ -106,10 +120,20 @@ "node": ">=6.9.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@bufbuild/protobuf": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.6.1.tgz", - "integrity": "sha512-DaG6XlyKpz08bmHY5SGX2gfIllaqtDJ/KwVoxsmP22COOLYwDBe7yD3DZGwXem/Xq7QOc9cuR7R3MpAv5CFfDw==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.7.0.tgz", + "integrity": "sha512-qn6tAIZEw5i/wiESBF4nQxZkl86aY4KoO0IkUa2Lh+rya64oTOdJQFlZuMwI1Qz9VBJQrQC4QlSA2DNek5gCOA==", "dev": true, "license": "(Apache-2.0 AND BSD-3-Clause)" }, @@ -389,9 +413,9 @@ } }, "node_modules/@csstools/color-helpers": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", - "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", + "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", "funding": [ { "type": "github", @@ -431,9 +455,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", - "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", + "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", "funding": [ { "type": "github", @@ -446,7 +470,7 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^5.0.2", + "@csstools/color-helpers": "^5.1.0", "@csstools/css-calc": "^2.1.4" }, "engines": { @@ -522,9 +546,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", - "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", "cpu": [ "ppc64" ], @@ -539,9 +563,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", - "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", "cpu": [ "arm" ], @@ -556,9 +580,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", - "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", "cpu": [ "arm64" ], @@ -573,9 +597,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", - "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", "cpu": [ "x64" ], @@ -590,9 +614,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", - "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", "cpu": [ "arm64" ], @@ -607,9 +631,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", - "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", "cpu": [ "x64" ], @@ -624,9 +648,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", - "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", "cpu": [ "arm64" ], @@ -641,9 +665,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", - "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", "cpu": [ "x64" ], @@ -658,9 +682,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", - "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", "cpu": [ "arm" ], @@ -675,9 +699,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", - "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", "cpu": [ "arm64" ], @@ -692,9 +716,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", - "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", "cpu": [ "ia32" ], @@ -709,9 +733,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", - "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", "cpu": [ "loong64" ], @@ -726,9 +750,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", - "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", "cpu": [ "mips64el" ], @@ -743,9 +767,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", - "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", "cpu": [ "ppc64" ], @@ -760,9 +784,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", - "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", "cpu": [ "riscv64" ], @@ -777,9 +801,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", - "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", "cpu": [ "s390x" ], @@ -794,9 +818,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", - "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", "cpu": [ "x64" ], @@ -811,9 +835,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", - "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", "cpu": [ "arm64" ], @@ -828,9 +852,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", - "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", "cpu": [ "x64" ], @@ -845,9 +869,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", - "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", "cpu": [ "arm64" ], @@ -862,9 +886,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", - "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", "cpu": [ "x64" ], @@ -879,9 +903,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", - "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", "cpu": [ "arm64" ], @@ -896,9 +920,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", - "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", "cpu": [ "x64" ], @@ -913,9 +937,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", - "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", "cpu": [ "arm64" ], @@ -930,9 +954,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", - "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", "cpu": [ "ia32" ], @@ -947,9 +971,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", - "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", "cpu": [ "x64" ], @@ -1129,9 +1153,9 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.2.tgz", - "integrity": "sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", "dev": true, "license": "MIT", "dependencies": { @@ -1139,13 +1163,13 @@ } }, "node_modules/@floating-ui/dom": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.2.tgz", - "integrity": "sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/core": "^1.7.2", + "@floating-ui/core": "^1.7.3", "@floating-ui/utils": "^0.2.10" } }, @@ -1276,12 +1300,12 @@ } }, "node_modules/@inquirer/checkbox": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.0.tgz", - "integrity": "sha512-fdSw07FLJEU5vbpOPzXo5c6xmMGDzbZE2+niuDHX5N6mc6V0Ebso/q3xiHra4D73+PMsC8MJmcaZKuAAoaQsSA==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.2.2.tgz", + "integrity": "sha512-E+KExNurKcUJJdxmjglTl141EwxWyAHplvsYJQgSwXf8qiNWkTxTuCCqmhFEmbIXd4zLaGMfQFJ6WrZ7fSeV3g==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", + "@inquirer/core": "^10.2.0", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", @@ -1327,12 +1351,12 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.14", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.14.tgz", - "integrity": "sha512-5yR4IBfe0kXe59r1YCTG8WXkUbl7Z35HK87Sw+WUyGD8wNUx7JvY7laahzeytyE1oLn74bQnL7hstctQxisQ8Q==", + "version": "5.1.16", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.16.tgz", + "integrity": "sha512-j1a5VstaK5KQy8Mu8cHmuQvN1Zc62TbLhjJxwHvKPPKEoowSF6h/0UdOpA9DNdWZ+9Inq73+puRq1df6OJ8Sag==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", + "@inquirer/core": "^10.2.0", "@inquirer/type": "^3.0.8" }, "engines": { @@ -1348,9 +1372,9 @@ } }, "node_modules/@inquirer/core": { - "version": "10.1.15", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.15.tgz", - "integrity": "sha512-8xrp836RZvKkpNbVvgWUlxjT4CraKk2q+I3Ksy+seI2zkcE+y6wNs1BVhgcv8VyImFecUhdQrYLdW32pAjwBdA==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.2.0.tgz", + "integrity": "sha512-NyDSjPqhSvpZEMZrLCYUquWNl+XC/moEcVFqS55IEYIYsY0a1cUCevSqk7ctOlnm/RaSBU5psFryNlxcmGrjaA==", "license": "MIT", "dependencies": { "@inquirer/figures": "^1.0.13", @@ -1481,14 +1505,14 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.15", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.15.tgz", - "integrity": "sha512-wst31XT8DnGOSS4nNJDIklGKnf+8shuauVrWzgKegWUe28zfCftcWZ2vktGdzJgcylWSS2SrDnYUb6alZcwnCQ==", + "version": "4.2.18", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.18.tgz", + "integrity": "sha512-yeQN3AXjCm7+Hmq5L6Dm2wEDeBRdAZuyZ4I7tWSSanbxDzqM0KqzoDbKM7p4ebllAYdoQuPJS6N71/3L281i6w==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", - "@inquirer/type": "^3.0.8", - "external-editor": "^3.1.0" + "@inquirer/core": "^10.2.0", + "@inquirer/external-editor": "^1.0.1", + "@inquirer/type": "^3.0.8" }, "engines": { "node": ">=18" @@ -1503,12 +1527,12 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.17.tgz", - "integrity": "sha512-PSqy9VmJx/VbE3CT453yOfNa+PykpKg/0SYP7odez1/NWBGuDXgPhp4AeGYYKjhLn5lUUavVS/JbeYMPdH50Mw==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.18.tgz", + "integrity": "sha512-xUjteYtavH7HwDMzq4Cn2X4Qsh5NozoDHCJTdoXg9HfZ4w3R6mxV1B9tL7DGJX2eq/zqtsFjhm0/RJIMGlh3ag==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", + "@inquirer/core": "^10.2.0", "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, @@ -1524,6 +1548,27 @@ } } }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.1.tgz", + "integrity": "sha512-Oau4yL24d2B5IL4ma4UpbQigkVhzPDXLoqy1ggK4gnHg/stmkffJE4oOXHXF3uz0UEpywG68KcyXsyYpA1Re/Q==", + "license": "MIT", + "dependencies": { + "chardet": "^2.1.0", + "iconv-lite": "^0.6.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, "node_modules/@inquirer/figures": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.13.tgz", @@ -1534,12 +1579,12 @@ } }, "node_modules/@inquirer/input": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.1.tgz", - "integrity": "sha512-tVC+O1rBl0lJpoUZv4xY+WGWY8V5b0zxU1XDsMsIHYregdh7bN5X5QnIONNBAl0K765FYlAfNHS2Bhn7SSOVow==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.2.tgz", + "integrity": "sha512-hqOvBZj/MhQCpHUuD3MVq18SSoDNHy7wEnQ8mtvs71K8OPZVXJinOzcvQna33dNYLYE4LkA9BlhAhK6MJcsVbw==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", + "@inquirer/core": "^10.2.0", "@inquirer/type": "^3.0.8" }, "engines": { @@ -1555,12 +1600,12 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.17.tgz", - "integrity": "sha512-GcvGHkyIgfZgVnnimURdOueMk0CztycfC8NZTiIY9arIAkeOgt6zG57G+7vC59Jns3UX27LMkPKnKWAOF5xEYg==", + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.18.tgz", + "integrity": "sha512-7exgBm52WXZRczsydCVftozFTrrwbG5ySE0GqUd2zLNSBXyIucs2Wnm7ZKLe/aUu6NUg9dg7Q80QIHCdZJiY4A==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", + "@inquirer/core": "^10.2.0", "@inquirer/type": "^3.0.8" }, "engines": { @@ -1576,12 +1621,12 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.17.tgz", - "integrity": "sha512-DJolTnNeZ00E1+1TW+8614F7rOJJCM4y4BAGQ3Gq6kQIG+OJ4zr3GLjIjVVJCbKsk2jmkmv6v2kQuN/vriHdZA==", + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.18.tgz", + "integrity": "sha512-zXvzAGxPQTNk/SbT3carAD4Iqi6A2JS2qtcqQjsL22uvD+JfQzUrDEtPjLL7PLn8zlSNyPdY02IiQjzoL9TStA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", + "@inquirer/core": "^10.2.0", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2" }, @@ -1625,21 +1670,21 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.7.1.tgz", - "integrity": "sha512-XDxPrEWeWUBy8scAXzXuFY45r/q49R0g72bUzgQXZ1DY/xEFX+ESDMkTQolcb5jRBzaNJX2W8XQl6krMNDTjaA==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.8.4.tgz", + "integrity": "sha512-MuxVZ1en1g5oGamXV3DWP89GEkdD54alcfhHd7InUW5BifAdKQEK9SLFa/5hlWbvuhMPlobF0WAx7Okq988Jxg==", "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.2.0", - "@inquirer/confirm": "^5.1.14", - "@inquirer/editor": "^4.2.15", - "@inquirer/expand": "^4.0.17", - "@inquirer/input": "^4.2.1", - "@inquirer/number": "^3.0.17", - "@inquirer/password": "^4.0.17", - "@inquirer/rawlist": "^4.1.5", - "@inquirer/search": "^3.0.17", - "@inquirer/select": "^4.3.1" + "@inquirer/checkbox": "^4.2.2", + "@inquirer/confirm": "^5.1.16", + "@inquirer/editor": "^4.2.18", + "@inquirer/expand": "^4.0.18", + "@inquirer/input": "^4.2.2", + "@inquirer/number": "^3.0.18", + "@inquirer/password": "^4.0.18", + "@inquirer/rawlist": "^4.1.6", + "@inquirer/search": "^3.1.1", + "@inquirer/select": "^4.3.2" }, "engines": { "node": ">=18" @@ -1654,12 +1699,12 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.5.tgz", - "integrity": "sha512-R5qMyGJqtDdi4Ht521iAkNqyB6p2UPuZUbMifakg1sWtu24gc2Z8CJuw8rP081OckNDMgtDCuLe42Q2Kr3BolA==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.6.tgz", + "integrity": "sha512-KOZqa3QNr3f0pMnufzL7K+nweFFCCBs6LCXZzXDrVGTyssjLeudn5ySktZYv1XiSqobyHRYYK0c6QsOxJEhXKA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", + "@inquirer/core": "^10.2.0", "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" }, @@ -1676,12 +1721,12 @@ } }, "node_modules/@inquirer/search": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.17.tgz", - "integrity": "sha512-CuBU4BAGFqRYors4TNCYzy9X3DpKtgIW4Boi0WNkm4Ei1hvY9acxKdBdyqzqBCEe4YxSdaQQsasJlFlUJNgojw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.1.1.tgz", + "integrity": "sha512-TkMUY+A2p2EYVY3GCTItYGvqT6LiLzHBnqsU1rJbrpXUijFfM6zvUx0R4civofVwFCmJZcKqOVwwWAjplKkhxA==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", + "@inquirer/core": "^10.2.0", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "yoctocolors-cjs": "^2.1.2" @@ -1699,12 +1744,12 @@ } }, "node_modules/@inquirer/select": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.1.tgz", - "integrity": "sha512-Gfl/5sqOF5vS/LIrSndFgOh7jgoe0UXEizDqahFRkq5aJBLegZ6WjuMh/hVEJwlFQjyLq1z9fRtvUMkb7jM1LA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.3.2.tgz", + "integrity": "sha512-nwous24r31M+WyDEHV+qckXkepvihxhnyIaod2MG7eCE6G0Zm/HUF6jgN8GXgf4U7AU6SLseKdanY195cwvU6w==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.1.15", + "@inquirer/core": "^10.2.0", "@inquirer/figures": "^1.0.13", "@inquirer/type": "^3.0.8", "ansi-escapes": "^4.3.2", @@ -1784,10 +1829,20 @@ "node": ">=12" } }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { @@ -1806,15 +1861,15 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", - "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2314,6 +2369,330 @@ "dev": true, "license": "MIT" }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/@phun-ky/typeof": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@phun-ky/typeof/-/typeof-1.2.8.tgz", @@ -2370,9 +2749,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.19", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.19.tgz", - "integrity": "sha512-3FL3mnMbPu0muGOCaKAhhFEYmqv9eTfPSJRJmANrCwtgK8VuxpsZDGK+m0LYAGoyO8+0j5uRe4PeyPDK1yA/hA==", + "version": "1.0.0-beta.29", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz", + "integrity": "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==", "dev": true, "license": "MIT" }, @@ -2445,9 +2824,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", - "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.48.1.tgz", + "integrity": "sha512-rGmb8qoG/zdmKoYELCBwu7vt+9HxZ7Koos3pD0+sH5fR3u3Wb/jGcpnqxcnWsPEKDUyzeLSqksN8LJtgXjqBYw==", "cpu": [ "arm" ], @@ -2459,9 +2838,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", - "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.48.1.tgz", + "integrity": "sha512-4e9WtTxrk3gu1DFE+imNJr4WsL13nWbD/Y6wQcyku5qadlKHY3OQ3LJ/INrrjngv2BJIHnIzbqMk1GTAC2P8yQ==", "cpu": [ "arm64" ], @@ -2473,9 +2852,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", - "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.48.1.tgz", + "integrity": "sha512-+XjmyChHfc4TSs6WUQGmVf7Hkg8ferMAE2aNYYWjiLzAS/T62uOsdfnqv+GHRjq7rKRnYh4mwWb4Hz7h/alp8A==", "cpu": [ "arm64" ], @@ -2487,9 +2866,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", - "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.48.1.tgz", + "integrity": "sha512-upGEY7Ftw8M6BAJyGwnwMw91rSqXTcOKZnnveKrVWsMTF8/k5mleKSuh7D4v4IV1pLxKAk3Tbs0Lo9qYmii5mQ==", "cpu": [ "x64" ], @@ -2501,9 +2880,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", - "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.48.1.tgz", + "integrity": "sha512-P9ViWakdoynYFUOZhqq97vBrhuvRLAbN/p2tAVJvhLb8SvN7rbBnJQcBu8e/rQts42pXGLVhfsAP0k9KXWa3nQ==", "cpu": [ "arm64" ], @@ -2515,9 +2894,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", - "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.48.1.tgz", + "integrity": "sha512-VLKIwIpnBya5/saccM8JshpbxfyJt0Dsli0PjXozHwbSVaHTvWXJH1bbCwPXxnMzU4zVEfgD1HpW3VQHomi2AQ==", "cpu": [ "x64" ], @@ -2529,9 +2908,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", - "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.48.1.tgz", + "integrity": "sha512-3zEuZsXfKaw8n/yF7t8N6NNdhyFw3s8xJTqjbTDXlipwrEHo4GtIKcMJr5Ed29leLpB9AugtAQpAHW0jvtKKaQ==", "cpu": [ "arm" ], @@ -2543,9 +2922,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", - "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.48.1.tgz", + "integrity": "sha512-leo9tOIlKrcBmmEypzunV/2w946JeLbTdDlwEZ7OnnsUyelZ72NMnT4B2vsikSgwQifjnJUbdXzuW4ToN1wV+Q==", "cpu": [ "arm" ], @@ -2557,9 +2936,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", - "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.48.1.tgz", + "integrity": "sha512-Vy/WS4z4jEyvnJm+CnPfExIv5sSKqZrUr98h03hpAMbE2aI0aD2wvK6GiSe8Gx2wGp3eD81cYDpLLBqNb2ydwQ==", "cpu": [ "arm64" ], @@ -2571,9 +2950,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", - "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.48.1.tgz", + "integrity": "sha512-x5Kzn7XTwIssU9UYqWDB9VpLpfHYuXw5c6bJr4Mzv9kIv242vmJHbI5PJJEnmBYitUIfoMCODDhR7KoZLot2VQ==", "cpu": [ "arm64" ], @@ -2585,9 +2964,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", - "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.48.1.tgz", + "integrity": "sha512-yzCaBbwkkWt/EcgJOKDUdUpMHjhiZT/eDktOPWvSRpqrVE04p0Nd6EGV4/g7MARXXeOqstflqsKuXVM3H9wOIQ==", "cpu": [ "loong64" ], @@ -2599,9 +2978,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", - "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.48.1.tgz", + "integrity": "sha512-UK0WzWUjMAJccHIeOpPhPcKBqax7QFg47hwZTp6kiMhQHeOYJeaMwzeRZe1q5IiTKsaLnHu9s6toSYVUlZ2QtQ==", "cpu": [ "ppc64" ], @@ -2613,9 +2992,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", - "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.48.1.tgz", + "integrity": "sha512-3NADEIlt+aCdCbWVZ7D3tBjBX1lHpXxcvrLt/kdXTiBrOds8APTdtk2yRL2GgmnSVeX4YS1JIf0imFujg78vpw==", "cpu": [ "riscv64" ], @@ -2627,9 +3006,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", - "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.48.1.tgz", + "integrity": "sha512-euuwm/QTXAMOcyiFCcrx0/S2jGvFlKJ2Iro8rsmYL53dlblp3LkUQVFzEidHhvIPPvcIsxDhl2wkBE+I6YVGzA==", "cpu": [ "riscv64" ], @@ -2641,9 +3020,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", - "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.48.1.tgz", + "integrity": "sha512-w8mULUjmPdWLJgmTYJx/W6Qhln1a+yqvgwmGXcQl2vFBkWsKGUBRbtLRuKJUln8Uaimf07zgJNxOhHOvjSQmBQ==", "cpu": [ "s390x" ], @@ -2655,9 +3034,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", - "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.48.1.tgz", + "integrity": "sha512-90taWXCWxTbClWuMZD0DKYohY1EovA+W5iytpE89oUPmT5O1HFdf8cuuVIylE6vCbrGdIGv85lVRzTcpTRZ+kA==", "cpu": [ "x64" ], @@ -2669,9 +3048,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", - "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.48.1.tgz", + "integrity": "sha512-2Gu29SkFh1FfTRuN1GR1afMuND2GKzlORQUP3mNMJbqdndOg7gNsa81JnORctazHRokiDzQ5+MLE5XYmZW5VWg==", "cpu": [ "x64" ], @@ -2683,9 +3062,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", - "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.48.1.tgz", + "integrity": "sha512-6kQFR1WuAO50bxkIlAVeIYsz3RUx+xymwhTo9j94dJ+kmHe9ly7muH23sdfWduD0BA8pD9/yhonUvAjxGh34jQ==", "cpu": [ "arm64" ], @@ -2697,9 +3076,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", - "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.48.1.tgz", + "integrity": "sha512-RUyZZ/mga88lMI3RlXFs4WQ7n3VyU07sPXmMG7/C1NOi8qisUg57Y7LRarqoGoAiopmGmChUhSwfpvQ3H5iGSQ==", "cpu": [ "ia32" ], @@ -2711,9 +3090,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", - "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.48.1.tgz", + "integrity": "sha512-8a/caCUN4vkTChxkaIJcMtwIVcBhi4X2PQRoT+yCK3qRYaZ7cURrmJFL5Ux9H9RaMIXj9RuihckdmkBX3zZsgg==", "cpu": [ "x64" ], @@ -2737,6 +3116,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@superdoc-dev/ooxml-inspector": { + "resolved": "packages/ooxml-inspector", + "link": true + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -2922,9 +3305,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.16.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.16.5.tgz", - "integrity": "sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==", + "version": "22.18.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.0.tgz", + "integrity": "sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==", "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -2981,9 +3364,9 @@ "license": "MIT" }, "node_modules/@typescript-eslint/types": { - "version": "8.39.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.1.tgz", - "integrity": "sha512-7sPDKQQp+S11laqTrhHqeAbsCfMkwJMrV7oTDvtDds4mEofJYir414bYKUEb8YPUm9QL3U+8f6L6YExSoAGdQw==", + "version": "8.41.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.41.0.tgz", + "integrity": "sha512-9EwxsWdVqh42afLbHP90n2VdHaWU/oWgbH2P0CfcNfdKL7CuKpwMQGjwev56vWu9cSKU7FWSu6r9zck6CVfnag==", "dev": true, "license": "MIT", "engines": { @@ -3002,13 +3385,13 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-vue": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.0.tgz", - "integrity": "sha512-iAliE72WsdhjzTOp2DtvKThq1VBC4REhwRcaA+zPAAph6I+OQhUXv+Xu2KS7ElxYtb7Zc/3R30Hwv1DxEo7NXQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz", + "integrity": "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-beta.19" + "@rolldown/pluginutils": "1.0.0-beta.29" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -3018,6 +3401,40 @@ "vue": "^3.2.25" } }, + "node_modules/@vitest/coverage-v8": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.4.tgz", + "integrity": "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "ast-v8-to-istanbul": "^0.3.3", + "debug": "^4.4.1", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.9.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "3.2.4", + "vitest": "3.2.4" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, "node_modules/@vitest/expect": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", @@ -3800,15 +4217,15 @@ } }, "node_modules/@vueuse/core": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.5.0.tgz", - "integrity": "sha512-wV7z0eUpifKmvmN78UBZX8T7lMW53Nrk6JP5+6hbzrB9+cJ3jr//hUlhl9TZO/03bUkMK6gGkQpqOPWoabr72g==", + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.7.0.tgz", + "integrity": "sha512-myagn09+c6BmS6yHc1gTwwsdZilAovHslMjyykmZH3JNyzI5HoWhv114IIdytXiPipdHJ2gDUx0PB93jRduJYg==", "dev": true, "license": "MIT", "dependencies": { "@types/web-bluetooth": "^0.0.21", - "@vueuse/metadata": "13.5.0", - "@vueuse/shared": "13.5.0" + "@vueuse/metadata": "13.7.0", + "@vueuse/shared": "13.7.0" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -3818,9 +4235,9 @@ } }, "node_modules/@vueuse/metadata": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.5.0.tgz", - "integrity": "sha512-euhItU3b0SqXxSy8u1XHxUCdQ8M++bsRs+TYhOLDU/OykS7KvJnyIFfep0XM5WjIFry9uAPlVSjmVHiqeshmkw==", + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.7.0.tgz", + "integrity": "sha512-8okFhS/1ite8EwUdZZfvTYowNTfXmVCOrBFlA31O0HD8HKXhY+WtTRyF0LwbpJfoFPc+s9anNJIXMVrvP7UTZg==", "dev": true, "license": "MIT", "funding": { @@ -3828,9 +4245,9 @@ } }, "node_modules/@vueuse/shared": { - "version": "13.5.0", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.5.0.tgz", - "integrity": "sha512-K7GrQIxJ/ANtucxIXbQlUHdB0TPA8c+q5i+zbrjxuhJCnJ9GtBg75sBSnvmLSxHKPg2Yo8w62PWksl9kwH0Q8g==", + "version": "13.7.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.7.0.tgz", + "integrity": "sha512-Wi2LpJi4UA9kM0OZ0FCZslACp92HlVNw1KPaDY6RAzvQ+J1s7seOtcOpmkfbD5aBSmMn9NvOakc8ZxMxmDXTIg==", "dev": true, "license": "MIT", "funding": { @@ -3923,9 +4340,9 @@ } }, "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.0.tgz", + "integrity": "sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==", "license": "MIT", "engines": { "node": ">=12" @@ -4098,6 +4515,35 @@ "node": ">=4" } }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.4.tgz", + "integrity": "sha512-cxrAnZNLBnQwBPByK4CeDaw5sWZtMilJE/Q3iDA0aamgaIVNDF9T6K2/8DfYDZEejZ2jNnDrG9m8MY72HFd0KA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.29", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/async-retry": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", @@ -4437,9 +4883,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", - "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "version": "4.25.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.3.tgz", + "integrity": "sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==", "dev": true, "funding": [ { @@ -4457,8 +4903,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001726", - "electron-to-chromium": "^1.5.173", + "caniuse-lite": "^1.0.30001735", + "electron-to-chromium": "^1.5.204", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -4660,9 +5106,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001727", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001727.tgz", - "integrity": "sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==", + "version": "1.0.30001737", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001737.tgz", + "integrity": "sha512-BiloLiXtQNrY5UyF0+1nSJLXUENuhka2pzy2Fx5pGxqavdrxSCW4U6Pn/PoG3Efspi2frRbHpBV2XsrPE6EDlw==", "dev": true, "funding": [ { @@ -4708,9 +5154,9 @@ } }, "node_modules/chai": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.1.tgz", - "integrity": "sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", "dev": true, "license": "MIT", "dependencies": { @@ -4725,9 +5171,9 @@ } }, "node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", + "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", "license": "MIT", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -4759,9 +5205,9 @@ } }, "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.0.tgz", + "integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==", "license": "MIT" }, "node_modules/check-error": { @@ -5188,19 +5634,18 @@ } }, "node_modules/concurrently": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.0.tgz", - "integrity": "sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^4.1.2", - "lodash": "^4.17.21", - "rxjs": "^7.8.1", - "shell-quote": "^1.8.1", - "supports-color": "^8.1.1", - "tree-kill": "^1.2.2", - "yargs": "^17.7.2" + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", @@ -5259,6 +5704,32 @@ "node": ">=8" } }, + "node_modules/concurrently/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/confbox": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", @@ -6435,9 +6906,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.188", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.188.tgz", - "integrity": "sha512-pfEx5CBFAocOKNrc+i5fSvhDaI1Vr9R9aT5uX1IzM3hhdL6k649wfuUcdUd9EZnmbE1xdfA51CwqQ61CO3Xl3g==", + "version": "1.5.209", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.209.tgz", + "integrity": "sha512-Xoz0uMrim9ZETCQt8UgM5FxQF9+imA7PBpokoGcZloA1uw2LeHzTlip5cb5KOAsXZLjh/moN2vReN3ZjJmjI9A==", "dev": true, "license": "ISC" }, @@ -6596,9 +7067,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.8", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", - "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -6609,32 +7080,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.8", - "@esbuild/android-arm": "0.25.8", - "@esbuild/android-arm64": "0.25.8", - "@esbuild/android-x64": "0.25.8", - "@esbuild/darwin-arm64": "0.25.8", - "@esbuild/darwin-x64": "0.25.8", - "@esbuild/freebsd-arm64": "0.25.8", - "@esbuild/freebsd-x64": "0.25.8", - "@esbuild/linux-arm": "0.25.8", - "@esbuild/linux-arm64": "0.25.8", - "@esbuild/linux-ia32": "0.25.8", - "@esbuild/linux-loong64": "0.25.8", - "@esbuild/linux-mips64el": "0.25.8", - "@esbuild/linux-ppc64": "0.25.8", - "@esbuild/linux-riscv64": "0.25.8", - "@esbuild/linux-s390x": "0.25.8", - "@esbuild/linux-x64": "0.25.8", - "@esbuild/netbsd-arm64": "0.25.8", - "@esbuild/netbsd-x64": "0.25.8", - "@esbuild/openbsd-arm64": "0.25.8", - "@esbuild/openbsd-x64": "0.25.8", - "@esbuild/openharmony-arm64": "0.25.8", - "@esbuild/sunos-x64": "0.25.8", - "@esbuild/win32-arm64": "0.25.8", - "@esbuild/win32-ia32": "0.25.8", - "@esbuild/win32-x64": "0.25.8" + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" } }, "node_modules/escalade": { @@ -6756,9 +7227,9 @@ } }, "node_modules/eslint-plugin-jsdoc": { - "version": "54.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-54.1.0.tgz", - "integrity": "sha512-tZJuW6s3gtveVsg08IbJgmfgAA1SpSkEz7KjxPEVmyAO4fPlz7zsMHdxjyn+Zku1l+wejr2JUdTFTNirRgHOrQ==", + "version": "54.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-54.1.1.tgz", + "integrity": "sha512-qoY2Gl0OkvATXIxRaG2irS2ue78+RTaOyYrADvg1ue+9FHE+2Mp7RcpO0epkuhhQgOkH/REv1oJFe58dYv8SGg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -6780,17 +7251,6 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, "node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -6888,6 +7348,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -7179,32 +7649,6 @@ "node": ">=0.10.0" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "license": "MIT", - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fast-content-type-parse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz", @@ -7271,9 +7715,9 @@ "license": "MIT" }, "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", "dev": true, "funding": [ { @@ -7297,10 +7741,13 @@ } }, "node_modules/fdir": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", - "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, "peerDependencies": { "picomatch": "^3 || ^4" }, @@ -7470,9 +7917,9 @@ } }, "node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", "dev": true, "license": "MIT", "dependencies": { @@ -7517,9 +7964,9 @@ "license": "ISC" }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -7800,6 +8247,24 @@ } } }, + "node_modules/git-semver-tags/node_modules/conventional-commits-parser": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.0.tgz", + "integrity": "sha512-uLnoLeIW4XaoFtH37qEcg/SXMJmKF4vi7V0H2rnPueg+VEtFGA/asSCNTcq4M/GQ6QmlzchAEtOoDTtKqWeHag==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "meow": "^13.0.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/git-up": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz", @@ -8010,13 +8475,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/gray-matter/node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -8040,13 +8498,13 @@ } }, "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-property-descriptors": { @@ -8328,6 +8786,13 @@ "node": ">=18" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/html-void-elements": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", @@ -8634,14 +9099,10 @@ } }, "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", + "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, "engines": { "node": ">= 12" } @@ -9046,6 +9507,99 @@ "node": "^18.17 || >=20.6.1" } }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jackspeak": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", @@ -9063,9 +9617,9 @@ } }, "node_modules/jiti": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", - "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -9133,12 +9687,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" - }, "node_modules/jsdoc-type-pratt-parser": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.8.0.tgz", @@ -9218,9 +9766,9 @@ "license": "MIT" }, "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", "dependencies": { @@ -9400,13 +9948,13 @@ } }, "node_modules/lint-staged": { - "version": "16.1.4", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.4.tgz", - "integrity": "sha512-xy7rnzQrhTVGKMpv6+bmIA3C0yET31x8OhKBYfvGo0/byeZ6E0BjGARrir3Kg/RhhYHutpsi01+2J5IpfVoueA==", + "version": "16.1.5", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.1.5.tgz", + "integrity": "sha512-uAeQQwByI6dfV7wpt/gVqg+jAPaSp8WwOA8kKC/dv1qw14oGpnpAisY65ibGHUGDUv0rYaZ8CAJZ/1U8hUvC2A==", "dev": true, "license": "MIT", "dependencies": { - "chalk": "^5.4.1", + "chalk": "^5.5.0", "commander": "^14.0.0", "debug": "^4.4.1", "lilconfig": "^3.1.3", @@ -9415,7 +9963,7 @@ "nano-spawn": "^1.0.2", "pidtree": "^0.6.0", "string-argv": "^0.3.2", - "yaml": "^2.8.0" + "yaml": "^2.8.1" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -9428,9 +9976,9 @@ } }, "node_modules/listr2": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.1.tgz", - "integrity": "sha512-SL0JY3DaxylDuo/MecFeiC+7pedM0zia33zl0vcjgwcq1q1FWWF1To9EIauPbl8GbMCU0R2e0uJ8bZunhYKD2g==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.2.tgz", + "integrity": "sha512-VVd7cS6W+vLJu2wmq4QmfVj14Iep7cz4r/OWNk36Aq5ZOY7G8/BfCrQFexcwB1OIxB3yERiePfE/REBjEFulag==", "dev": true, "license": "MIT", "dependencies": { @@ -9750,9 +10298,9 @@ } }, "node_modules/loupe": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.4.tgz", - "integrity": "sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", "dev": true, "license": "MIT" }, @@ -9775,12 +10323,24 @@ } }, "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "version": "0.30.18", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz", + "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" } }, "node_modules/make-dir": { @@ -10234,16 +10794,16 @@ } }, "node_modules/mlly": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", - "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz", + "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==", "dev": true, "license": "MIT", "dependencies": { - "acorn": "^8.14.0", - "pathe": "^2.0.1", - "pkg-types": "^1.3.0", - "ufo": "^1.5.4" + "acorn": "^8.15.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.1" } }, "node_modules/mlly/node_modules/confbox": { @@ -10410,6 +10970,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -10432,9 +11000,9 @@ } }, "node_modules/node-fetch-native": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.6.tgz", - "integrity": "sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", "license": "MIT" }, "node_modules/node-fetch/node_modules/tr46": { @@ -10575,16 +11143,6 @@ "node": ">= 6" } }, - "node_modules/nodemon/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/nodemon/node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", @@ -10597,31 +11155,18 @@ "funding": { "url": "https://github.com/sponsors/jonschlinkert" } - }, - "node_modules/nodemon/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/nodemon/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + }, + "node_modules/nodemon/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "picomatch": "^2.2.1" }, "engines": { - "node": ">=4" + "node": ">=8.10.0" } }, "node_modules/nopt": { @@ -10730,22 +11275,22 @@ } }, "node_modules/nwsapi": { - "version": "2.2.20", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", - "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", + "version": "2.2.21", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.21.tgz", + "integrity": "sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==", "license": "MIT" }, "node_modules/nypm": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.0.tgz", - "integrity": "sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.1.tgz", + "integrity": "sha512-hlacBiRiv1k9hZFiphPUkfSQ/ZfQzZDzC+8z0wL3lvDAOUu/2NnChkKuMoMjNur/9OpKuz2QsIeiPVN0xM5Q0w==", "license": "MIT", "dependencies": { "citty": "^0.1.6", - "consola": "^3.4.0", + "consola": "^3.4.2", "pathe": "^2.0.3", - "pkg-types": "^2.0.0", - "tinyexec": "^0.3.2" + "pkg-types": "^2.2.0", + "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" @@ -10754,12 +11299,6 @@ "node": "^14.16.0 || >=16.10.0" } }, - "node_modules/nypm/node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "license": "MIT" - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -10972,15 +11511,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/p-limit": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", @@ -11540,9 +12070,9 @@ } }, "node_modules/pkg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.2.0.tgz", - "integrity": "sha512-2SM/GZGAEkPp3KWORxQZns4M+WSeXbC2HEvmOIJe3Cmiv6ieAJvdVhDldtHqM5J1Y7MrR1XhkBT/rMlhh9FdqQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", "license": "MIT", "dependencies": { "confbox": "^0.2.2", @@ -11814,9 +12344,9 @@ } }, "node_modules/prosemirror-model": { - "version": "1.25.2", - "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.2.tgz", - "integrity": "sha512-BVypCAJ4SL6jOiTsDffP3Wp6wD69lRhI4zg/iT8JXjp3ccZFiq5WyguxvMKmdKFC3prhaig7wSr8dneDToHE1Q==", + "version": "1.25.3", + "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.25.3.tgz", + "integrity": "sha512-dY2HdaNXlARknJbrManZ1WyUtos+AP97AmvqdOQtWtrrC5g4mohVX5DTi9rXNFSk09eczLq9GuNTtq3EfMeMGA==", "license": "MIT", "dependencies": { "orderedmap": "^2.0.0" @@ -12419,9 +12949,9 @@ } }, "node_modules/rollup": { - "version": "4.46.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", - "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", + "version": "4.48.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.48.1.tgz", + "integrity": "sha512-jVG20NvbhTYDkGAty2/Yh7HK6/q3DGSRH4o8ALKGArmMuaauM9kLfoMZ+WliPwA5+JHr2lTn3g557FxBV87ifg==", "dev": true, "license": "MIT", "dependencies": { @@ -12435,26 +12965,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.46.2", - "@rollup/rollup-android-arm64": "4.46.2", - "@rollup/rollup-darwin-arm64": "4.46.2", - "@rollup/rollup-darwin-x64": "4.46.2", - "@rollup/rollup-freebsd-arm64": "4.46.2", - "@rollup/rollup-freebsd-x64": "4.46.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", - "@rollup/rollup-linux-arm-musleabihf": "4.46.2", - "@rollup/rollup-linux-arm64-gnu": "4.46.2", - "@rollup/rollup-linux-arm64-musl": "4.46.2", - "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", - "@rollup/rollup-linux-ppc64-gnu": "4.46.2", - "@rollup/rollup-linux-riscv64-gnu": "4.46.2", - "@rollup/rollup-linux-riscv64-musl": "4.46.2", - "@rollup/rollup-linux-s390x-gnu": "4.46.2", - "@rollup/rollup-linux-x64-gnu": "4.46.2", - "@rollup/rollup-linux-x64-musl": "4.46.2", - "@rollup/rollup-win32-arm64-msvc": "4.46.2", - "@rollup/rollup-win32-ia32-msvc": "4.46.2", - "@rollup/rollup-win32-x64-msvc": "4.46.2", + "@rollup/rollup-android-arm-eabi": "4.48.1", + "@rollup/rollup-android-arm64": "4.48.1", + "@rollup/rollup-darwin-arm64": "4.48.1", + "@rollup/rollup-darwin-x64": "4.48.1", + "@rollup/rollup-freebsd-arm64": "4.48.1", + "@rollup/rollup-freebsd-x64": "4.48.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.48.1", + "@rollup/rollup-linux-arm-musleabihf": "4.48.1", + "@rollup/rollup-linux-arm64-gnu": "4.48.1", + "@rollup/rollup-linux-arm64-musl": "4.48.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.48.1", + "@rollup/rollup-linux-ppc64-gnu": "4.48.1", + "@rollup/rollup-linux-riscv64-gnu": "4.48.1", + "@rollup/rollup-linux-riscv64-musl": "4.48.1", + "@rollup/rollup-linux-s390x-gnu": "4.48.1", + "@rollup/rollup-linux-x64-gnu": "4.48.1", + "@rollup/rollup-linux-x64-musl": "4.48.1", + "@rollup/rollup-win32-arm64-msvc": "4.48.1", + "@rollup/rollup-win32-ia32-msvc": "4.48.1", + "@rollup/rollup-win32-x64-msvc": "4.48.1", "fsevents": "~2.3.2" } }, @@ -12659,13 +13189,13 @@ } }, "node_modules/rollup-plugin-visualizer/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", "dev": true, "license": "BSD-3-Clause", "engines": { - "node": ">= 8" + "node": ">= 12" } }, "node_modules/rope-sequence": { @@ -12778,10 +13308,32 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "license": "MIT" }, + "node_modules/sass": { + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.91.0.tgz", + "integrity": "sha512-aFOZHGf+ur+bp1bCHZ+u8otKGh77ZtmFyXDo4tlYvT7PWql41Kwd8wdkPqhhT+h2879IVblcHFglIMofsFd1EA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, "node_modules/sass-embedded": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.89.2.tgz", - "integrity": "sha512-Ack2K8rc57kCFcYlf3HXpZEJFNUX8xd8DILldksREmYXQkRHI879yy8q4mRDJgrojkySMZqmmmW1NxrFxMsYaA==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded/-/sass-embedded-1.91.0.tgz", + "integrity": "sha512-VTckYcH1AglrZ3VpPETilTo3Ef472XKwP13lrNfbOHSR6Eo5p27XTkIi+6lrCbuhBFFGAmy+4BRoLaeFUgn+eg==", "dev": true, "license": "MIT", "dependencies": { @@ -12801,28 +13353,47 @@ "node": ">=16.0.0" }, "optionalDependencies": { - "sass-embedded-android-arm": "1.89.2", - "sass-embedded-android-arm64": "1.89.2", - "sass-embedded-android-riscv64": "1.89.2", - "sass-embedded-android-x64": "1.89.2", - "sass-embedded-darwin-arm64": "1.89.2", - "sass-embedded-darwin-x64": "1.89.2", - "sass-embedded-linux-arm": "1.89.2", - "sass-embedded-linux-arm64": "1.89.2", - "sass-embedded-linux-musl-arm": "1.89.2", - "sass-embedded-linux-musl-arm64": "1.89.2", - "sass-embedded-linux-musl-riscv64": "1.89.2", - "sass-embedded-linux-musl-x64": "1.89.2", - "sass-embedded-linux-riscv64": "1.89.2", - "sass-embedded-linux-x64": "1.89.2", - "sass-embedded-win32-arm64": "1.89.2", - "sass-embedded-win32-x64": "1.89.2" + "sass-embedded-all-unknown": "1.91.0", + "sass-embedded-android-arm": "1.91.0", + "sass-embedded-android-arm64": "1.91.0", + "sass-embedded-android-riscv64": "1.91.0", + "sass-embedded-android-x64": "1.91.0", + "sass-embedded-darwin-arm64": "1.91.0", + "sass-embedded-darwin-x64": "1.91.0", + "sass-embedded-linux-arm": "1.91.0", + "sass-embedded-linux-arm64": "1.91.0", + "sass-embedded-linux-musl-arm": "1.91.0", + "sass-embedded-linux-musl-arm64": "1.91.0", + "sass-embedded-linux-musl-riscv64": "1.91.0", + "sass-embedded-linux-musl-x64": "1.91.0", + "sass-embedded-linux-riscv64": "1.91.0", + "sass-embedded-linux-x64": "1.91.0", + "sass-embedded-unknown-all": "1.91.0", + "sass-embedded-win32-arm64": "1.91.0", + "sass-embedded-win32-x64": "1.91.0" + } + }, + "node_modules/sass-embedded-all-unknown": { + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-all-unknown/-/sass-embedded-all-unknown-1.91.0.tgz", + "integrity": "sha512-AXC1oPqDfLnLtcoxM+XwSnbhcQs0TxAiA5JDEstl6+tt6fhFLKxdyl1Hla39SFtxvMfB2QDUYE3Dmx49O59vYg==", + "cpu": [ + "!arm", + "!arm64", + "!riscv64", + "!x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "sass": "1.91.0" } }, "node_modules/sass-embedded-android-arm": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.89.2.tgz", - "integrity": "sha512-oHAPTboBHRZlDBhyRB6dvDKh4KvFs+DZibDHXbkSI6dBZxMTT+Yb2ivocHnctVGucKTLQeT7+OM5DjWHyynL/A==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm/-/sass-embedded-android-arm-1.91.0.tgz", + "integrity": "sha512-DSh1V8TlLIcpklAbn4NINEFs3yD2OzVTbawEXK93IH990upoGNFVNRTstFQ/gcvlbWph3Y3FjAJvo37zUO485A==", "cpu": [ "arm" ], @@ -12837,9 +13408,9 @@ } }, "node_modules/sass-embedded-android-arm64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.89.2.tgz", - "integrity": "sha512-+pq7a7AUpItNyPu61sRlP6G2A8pSPpyazASb+8AK2pVlFayCSPAEgpwpCE9A2/Xj86xJZeMizzKUHxM2CBCUxA==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-arm64/-/sass-embedded-android-arm64-1.91.0.tgz", + "integrity": "sha512-I8Eeg2CeVcZIhXcQLNEY6ZBRF0m7jc818/fypwMwvIdbxGWBekTzc3aKHTLhdBpFzGnDIyR4s7oB0/OjIpzD1A==", "cpu": [ "arm64" ], @@ -12854,9 +13425,9 @@ } }, "node_modules/sass-embedded-android-riscv64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.89.2.tgz", - "integrity": "sha512-HfJJWp/S6XSYvlGAqNdakeEMPOdhBkj2s2lN6SHnON54rahKem+z9pUbCriUJfM65Z90lakdGuOfidY61R9TYg==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-riscv64/-/sass-embedded-android-riscv64-1.91.0.tgz", + "integrity": "sha512-qmsl1a7IIJL0fCOwzmRB+6nxeJK5m9/W8LReXUrdgyJNH5RyxChDg+wwQPVATFffOuztmWMnlJ5CV2sCLZrXcQ==", "cpu": [ "riscv64" ], @@ -12871,9 +13442,9 @@ } }, "node_modules/sass-embedded-android-x64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.89.2.tgz", - "integrity": "sha512-BGPzq53VH5z5HN8de6jfMqJjnRe1E6sfnCWFd4pK+CAiuM7iw5Fx6BQZu3ikfI1l2GY0y6pRXzsVLdp/j4EKEA==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-android-x64/-/sass-embedded-android-x64-1.91.0.tgz", + "integrity": "sha512-/wN0HBLATOVSeN3Tzg0yxxNTo1IQvOxxxwFv7Ki/1/UCg2AqZPxTpNoZj/mn8tUPtiVogMGbC8qclYMq1aRZsQ==", "cpu": [ "x64" ], @@ -12888,9 +13459,9 @@ } }, "node_modules/sass-embedded-darwin-arm64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.89.2.tgz", - "integrity": "sha512-UCm3RL/tzMpG7DsubARsvGUNXC5pgfQvP+RRFJo9XPIi6elopY5B6H4m9dRYDpHA+scjVthdiDwkPYr9+S/KGw==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-arm64/-/sass-embedded-darwin-arm64-1.91.0.tgz", + "integrity": "sha512-gQ6ScInxAN+BDUXy426BSYLRawkmGYlHpQ9i6iOxorr64dtIb3l6eb9YaBV8lPlroUnugylmwN2B3FU9BuPfhA==", "cpu": [ "arm64" ], @@ -12905,9 +13476,9 @@ } }, "node_modules/sass-embedded-darwin-x64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.89.2.tgz", - "integrity": "sha512-D9WxtDY5VYtMApXRuhQK9VkPHB8R79NIIR6xxVlN2MIdEid/TZWi1MHNweieETXhWGrKhRKglwnHxxyKdJYMnA==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-darwin-x64/-/sass-embedded-darwin-x64-1.91.0.tgz", + "integrity": "sha512-DSvFMtECL2blYVTFMO5fLeNr5bX437Lrz8R47fdo5438TRyOkSgwKTkECkfh3YbnrL86yJIN2QQlmBMF17Z/iw==", "cpu": [ "x64" ], @@ -12922,9 +13493,9 @@ } }, "node_modules/sass-embedded-linux-arm": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.89.2.tgz", - "integrity": "sha512-leP0t5U4r95dc90o8TCWfxNXwMAsQhpWxTkdtySDpngoqtTy3miMd7EYNYd1znI0FN1CBaUvbdCMbnbPwygDlA==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm/-/sass-embedded-linux-arm-1.91.0.tgz", + "integrity": "sha512-ppAZLp3eZ9oTjYdQDf4nM7EehDpkxq5H1hE8FOrx8LpY7pxn6QF+SRpAbRjdfFChRw0K7vh+IiCnQEMp7uLNAg==", "cpu": [ "arm" ], @@ -12939,9 +13510,9 @@ } }, "node_modules/sass-embedded-linux-arm64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.89.2.tgz", - "integrity": "sha512-2N4WW5LLsbtrWUJ7iTpjvhajGIbmDR18ZzYRywHdMLpfdPApuHPMDF5CYzHbS+LLx2UAx7CFKBnj5LLjY6eFgQ==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-arm64/-/sass-embedded-linux-arm64-1.91.0.tgz", + "integrity": "sha512-OnKCabD7f420ZEC/6YI9WhCVGMZF+ybZ5NbAB9SsG1xlxrKbWQ1s7CIl0w/6RDALtJ+Fjn8+mrxsxqakoAkeuA==", "cpu": [ "arm64" ], @@ -12956,9 +13527,9 @@ } }, "node_modules/sass-embedded-linux-musl-arm": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.89.2.tgz", - "integrity": "sha512-Z6gG2FiVEEdxYHRi2sS5VIYBmp17351bWtOCUZ/thBM66+e70yiN6Eyqjz80DjL8haRUegNQgy9ZJqsLAAmr9g==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm/-/sass-embedded-linux-musl-arm-1.91.0.tgz", + "integrity": "sha512-znEsNC2FurPF9+XwQQ6e/fVoic3e5D3/kMB41t/bE8byJVRdaPhkdsszt3pZUE56nNGYoCuieSXUkk7VvyPHsw==", "cpu": [ "arm" ], @@ -12973,9 +13544,9 @@ } }, "node_modules/sass-embedded-linux-musl-arm64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.89.2.tgz", - "integrity": "sha512-nTyuaBX6U1A/cG7WJh0pKD1gY8hbg1m2SnzsyoFG+exQ0lBX/lwTLHq3nyhF+0atv7YYhYKbmfz+sjPP8CZ9lw==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-arm64/-/sass-embedded-linux-musl-arm64-1.91.0.tgz", + "integrity": "sha512-VfbPpID1C5TT7rukob6CKgefx/TsLE+XZieMNd00hvfJ8XhqPr5DGvSMCNpXlwaedzTirbJu357m+n2PJI9TFQ==", "cpu": [ "arm64" ], @@ -12990,9 +13561,9 @@ } }, "node_modules/sass-embedded-linux-musl-riscv64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.89.2.tgz", - "integrity": "sha512-N6oul+qALO0SwGY8JW7H/Vs0oZIMrRMBM4GqX3AjM/6y8JsJRxkAwnfd0fDyK+aICMFarDqQonQNIx99gdTZqw==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-riscv64/-/sass-embedded-linux-musl-riscv64-1.91.0.tgz", + "integrity": "sha512-ZfLGldKEEeZjuljKks835LTq7jDRI3gXsKKXXgZGzN6Yymd4UpBOGWiDQlWsWTvw5UwDU2xfFh0wSXbLGHTjVA==", "cpu": [ "riscv64" ], @@ -13007,9 +13578,9 @@ } }, "node_modules/sass-embedded-linux-musl-x64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.89.2.tgz", - "integrity": "sha512-K+FmWcdj/uyP8GiG9foxOCPfb5OAZG0uSVq80DKgVSC0U44AdGjvAvVZkrgFEcZ6cCqlNC2JfYmslB5iqdL7tg==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-musl-x64/-/sass-embedded-linux-musl-x64-1.91.0.tgz", + "integrity": "sha512-4kSiSGPKFMbLvTRbP/ibyiKheOA3fwsJKWU0SOuekSPmybMdrhNkTm0REp6+nehZRE60kC3lXmEV4a7w8Jrwyg==", "cpu": [ "x64" ], @@ -13024,9 +13595,9 @@ } }, "node_modules/sass-embedded-linux-riscv64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.89.2.tgz", - "integrity": "sha512-g9nTbnD/3yhOaskeqeBQETbtfDQWRgsjHok6bn7DdAuwBsyrR3JlSFyqKc46pn9Xxd9SQQZU8AzM4IR+sY0A0w==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-riscv64/-/sass-embedded-linux-riscv64-1.91.0.tgz", + "integrity": "sha512-Y3Fj94SYYvMX9yo49T78yBgBWXtG3EyYUT5K05XyCYkcdl1mVXJSrEmqmRfe4vQGUCaSe/6s7MmsA9Q+mQez7Q==", "cpu": [ "riscv64" ], @@ -13041,9 +13612,9 @@ } }, "node_modules/sass-embedded-linux-x64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.89.2.tgz", - "integrity": "sha512-Ax7dKvzncyQzIl4r7012KCMBvJzOz4uwSNoyoM5IV6y5I1f5hEwI25+U4WfuTqdkv42taCMgpjZbh9ERr6JVMQ==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-linux-x64/-/sass-embedded-linux-x64-1.91.0.tgz", + "integrity": "sha512-XwIUaE7pQP/ezS5te80hlyheYiUlo0FolQ0HBtxohpavM+DVX2fjwFm5LOUJHrLAqP+TLBtChfFeLj1Ie4Aenw==", "cpu": [ "x64" ], @@ -13057,10 +13628,27 @@ "node": ">=14.0.0" } }, + "node_modules/sass-embedded-unknown-all": { + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-unknown-all/-/sass-embedded-unknown-all-1.91.0.tgz", + "integrity": "sha512-Bj6v7ScQp/HtO91QBy6ood9AArSIN7/RNcT4E7P9QoY3o+e6621Vd28lV81vdepPrt6u6PgJoVKmLNODqB6Q+A==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "!android", + "!darwin", + "!linux", + "!win32" + ], + "dependencies": { + "sass": "1.91.0" + } + }, "node_modules/sass-embedded-win32-arm64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.89.2.tgz", - "integrity": "sha512-j96iJni50ZUsfD6tRxDQE2QSYQ2WrfHxeiyAXf41Kw0V4w5KYR/Sf6rCZQLMTUOHnD16qTMVpQi20LQSqf4WGg==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-arm64/-/sass-embedded-win32-arm64-1.91.0.tgz", + "integrity": "sha512-yDCwTiPRex03i1yo7LwiAl1YQ21UyfOxPobD7UjI8AE8ZcB0mQ28VVX66lsZ+qm91jfLslNFOFCD4v79xCG9hA==", "cpu": [ "arm64" ], @@ -13075,9 +13663,9 @@ } }, "node_modules/sass-embedded-win32-x64": { - "version": "1.89.2", - "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.89.2.tgz", - "integrity": "sha512-cS2j5ljdkQsb4PaORiClaVYynE9OAPZG/XjbOMxpQmjRIf7UroY4PEIH+Waf+y47PfXFX9SyxhYuw2NIKGbEng==", + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/sass-embedded-win32-x64/-/sass-embedded-win32-x64-1.91.0.tgz", + "integrity": "sha512-wiuMz/cx4vsk6rYCnNyoGE5pd73aDJ/zF3qJDose3ZLT1/vV943doJE5pICnS/v5DrUqzV6a1CNq4fN+xeSgFQ==", "cpu": [ "x64" ], @@ -13091,6 +13679,32 @@ "node": ">=14.0.0" } }, + "node_modules/sass-embedded/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sass-embedded/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/sax": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", @@ -13436,12 +14050,12 @@ } }, "node_modules/socks": { - "version": "2.8.6", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.6.tgz", - "integrity": "sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==", + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "license": "MIT", "dependencies": { - "ip-address": "^9.0.5", + "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" }, "engines": { @@ -13512,6 +14126,17 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", @@ -13520,9 +14145,9 @@ "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13531,9 +14156,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", - "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", "dev": true, "license": "CC0-1.0" }, @@ -13558,9 +14183,10 @@ } }, "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/stackback": { @@ -13863,19 +14489,16 @@ } }, "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -13948,6 +14571,47 @@ "node": ">=8" } }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/text-extensions": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", @@ -14015,7 +14679,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", - "dev": true, "license": "MIT" }, "node_modules/tinyglobby": { @@ -14098,18 +14761,6 @@ "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", "license": "MIT" }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/to-buffer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.1.tgz", @@ -14298,6 +14949,7 @@ "version": "0.8.0-beta.0", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "deprecated": "The work that was done in this beta branch won't be included in future versions", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -14399,9 +15051,9 @@ "license": "MIT" }, "node_modules/typescript": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "devOptional": true, "license": "Apache-2.0", "bin": { @@ -14448,9 +15100,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.12.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.12.0.tgz", - "integrity": "sha512-GrKEsc3ughskmGA9jevVlIOPMiiAHJ4OFUtaAH+NhfTUSiZ1wMPIQqQvAJUrJspFXJt3EBWgpAeoHEDVT1IBug==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.15.0.tgz", + "integrity": "sha512-7oZJCPvvMvTd0OlqWsIxTuItTpJBpU1tcbVl24FMn3xt3+VSunwUasmfPJRE57oNO1KsZ4PgA1xTdAX4hq8NyQ==", "dev": true, "license": "MIT", "engines": { @@ -14721,6 +15373,17 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/varint": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/varint/-/varint-6.0.0.tgz", @@ -14771,9 +15434,9 @@ } }, "node_modules/vfile-message": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", - "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", "dev": true, "license": "MIT", "dependencies": { @@ -14786,15 +15449,15 @@ } }, "node_modules/vite": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.5.tgz", - "integrity": "sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz", + "integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", - "picomatch": "^4.0.2", + "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.40.0", "tinyglobby": "^0.2.14" @@ -14900,21 +15563,6 @@ "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, - "node_modules/vite/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/vitest": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", @@ -15069,14 +15717,14 @@ } }, "node_modules/vue-draggable-next": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vue-draggable-next/-/vue-draggable-next-2.2.1.tgz", - "integrity": "sha512-EAMS1IRHF0kZO0o5PMOinsQsXIqsrKT1hKmbICxG3UEtn7zLFkLxlAtajcCcUTisNvQ6TtCB5COjD9a1raNADw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/vue-draggable-next/-/vue-draggable-next-2.3.0.tgz", + "integrity": "sha512-ymbY0UIwfSdg0iDN/iyNNwUrTqZ/6KbPryzsvTNXBLuDCuOBdNijSK8yynNtmiSj6RapTPQfjLGQdJrZkzBd2w==", "dev": true, "license": "MIT", "peerDependencies": { "sortablejs": "^1.14.0", - "vue": "^3.2.2" + "vue": "^3.5.17" } }, "node_modules/vue-router": { @@ -15643,9 +16291,9 @@ "optional": true }, "node_modules/yaml": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", - "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", "dev": true, "license": "ISC", "bin": { @@ -15770,9 +16418,9 @@ } }, "node_modules/yoctocolors-cjs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", - "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", "license": "MIT", "engines": { "node": ">=18" @@ -15817,11 +16465,72 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "packages/ooxml-inspector": { + "name": "@superdoc-dev/ooxml-inspector", + "version": "1.0.0", + "license": "AGPL-3.0", + "dependencies": { + "fast-xml-parser": "^4.4.0" + }, + "bin": { + "ooxml": "dist/bin/cli.js" + }, + "devDependencies": { + "@types/node": "^24.3.0", + "@vitest/coverage-v8": "^3.2.4", + "tsup": "^8.1.0", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + }, + "engines": { + "node": ">=18.17" + } + }, + "packages/ooxml-inspector/node_modules/@types/node": { + "version": "24.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "packages/ooxml-inspector/node_modules/fast-xml-parser": { + "version": "4.5.3", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.1.1" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "packages/ooxml-inspector/node_modules/strnum": { + "version": "1.1.2", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "packages/ooxml-inspector/node_modules/undici-types": { + "version": "7.10.0", + "dev": true, + "license": "MIT" + }, "packages/super-editor": { "name": "@harbour-enterprises/super-editor", "version": "0.0.1", "license": "AGPL-3.0", "dependencies": { + "@superdoc-dev/ooxml-inspector": "^1.0.0", "color2k": "^2.0.3", "eventemitter3": "^5.0.1", "he": "^1.2.0", @@ -15882,21 +16591,6 @@ "vue": "^3.2.25" } }, - "packages/super-editor/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "packages/super-editor/node_modules/vite": { "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", @@ -15974,7 +16668,7 @@ }, "packages/superdoc": { "name": "@harbour-enterprises/superdoc", - "version": "0.15.16-next.11", + "version": "0.15.17-next.2", "license": "AGPL-3.0", "dependencies": { "buffer-crc32": "^1.0.0", @@ -16022,21 +16716,6 @@ "vue": "^3.2.25" } }, - "packages/superdoc/node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "packages/superdoc/node_modules/vite": { "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", diff --git a/packages/ooxml-inspector/.gitignore b/packages/ooxml-inspector/.gitignore new file mode 100644 index 0000000000..8b0dedc084 --- /dev/null +++ b/packages/ooxml-inspector/.gitignore @@ -0,0 +1,3 @@ +coverage/ +dist/ +node_modules/ \ No newline at end of file diff --git a/packages/ooxml-inspector/README.md b/packages/ooxml-inspector/README.md new file mode 100644 index 0000000000..5dc32063d7 --- /dev/null +++ b/packages/ooxml-inspector/README.md @@ -0,0 +1,51 @@ +# OOXML Inspector + +**OOXML Inspector** is a developer tool + library for working with [Office Open XML (OOXML)](https://en.wikipedia.org/wiki/Office_Open_XML) schemas. +It bundles the transitional WordprocessingML schema into JSON and provides both: + +- a **CLI** (`ooxml`) for inspecting schema relationships, and +- a **JavaScript/TypeScript library** for programmatic access. + +## Features + +- Query OOXML element children, attributes, and namespaces +- Explore schema relationships and tag hierarchies +- Use as a CLI or import as a library in Node.js/TypeScript + +## Installation + +```bash +npm install @superdoc-dev/ooxml-inspector +``` + +## CLI Usage + +```bash +npx ooxml children w:p +npx ooxml tags --parents +npx ooxml namespaces +npx ooxml attrs w:p +``` + +- `children `: List allowed children for an element +- `tags [prefix] [--parents] [--plain]`: List tags, optionally filtering by namespace or parent status +- `namespaces`: List all namespaces in the schema +- `attrs `: List attributes for an element + +## Library Usage + +```js +import { childrenOf } from '@superdoc-dev/ooxml-inspector'; + +const children = childrenOf('w:p'); // Get children of +``` + +## Development + +- Build: `npm run build` +- Test: `npm run test` +- Coverage: `npm run test:cov` + +## License + +AGPLv3 diff --git a/packages/ooxml-inspector/example/index.js b/packages/ooxml-inspector/example/index.js new file mode 100644 index 0000000000..fd918e7b25 --- /dev/null +++ b/packages/ooxml-inspector/example/index.js @@ -0,0 +1,4 @@ +import { childrenOf } from '@superdoc-dev/ooxml-inspector'; + +const children = childrenOf('w:p'); +console.debug('Children of w:p', children); diff --git a/packages/ooxml-inspector/generator/index.js b/packages/ooxml-inspector/generator/index.js new file mode 100644 index 0000000000..89632cd3d3 --- /dev/null +++ b/packages/ooxml-inspector/generator/index.js @@ -0,0 +1,3 @@ +import { runGenerator } from './src/index.js'; + +runGenerator(); diff --git a/packages/ooxml-inspector/generator/src/builder/autoprefix.js b/packages/ooxml-inspector/generator/src/builder/autoprefix.js new file mode 100644 index 0000000000..cf66e82127 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/autoprefix.js @@ -0,0 +1,13 @@ +/** + * Auto-assign a prefix for a given target namespace. + * @param {string} tns - The target namespace + * @param {Object} nsMap - The namespace map + * @returns {string} - The assigned prefix + */ +export const autoPrefix = (tns, nsMap) => { + if (!tns) return 'unknown'; + if (nsMap[tns]) return nsMap[tns]; + const newPrefix = 'g' + Object.keys(nsMap).length; + nsMap[tns] = newPrefix; + return newPrefix; +}; diff --git a/packages/ooxml-inspector/generator/src/builder/autoprefix.test.js b/packages/ooxml-inspector/generator/src/builder/autoprefix.test.js new file mode 100644 index 0000000000..cb2e212472 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/autoprefix.test.js @@ -0,0 +1,43 @@ +import { describe, it, expect } from 'vitest'; +import { autoPrefix } from './index.js'; + +describe('autoPrefix', () => { + it('returns "unknown" if tns is falsy', () => { + const nsMap = {}; + expect(autoPrefix('', nsMap)).toBe('unknown'); + expect(autoPrefix(null, nsMap)).toBe('unknown'); + expect(autoPrefix(undefined, nsMap)).toBe('unknown'); + }); + + it('returns existing prefix if tns is already in nsMap', () => { + const nsMap = { 'http://example.com': 'ex' }; + const result = autoPrefix('http://example.com', nsMap); + expect(result).toBe('ex'); + expect(nsMap).toEqual({ 'http://example.com': 'ex' }); // unchanged + }); + + it('assigns a new prefix if tns is not in nsMap', () => { + const nsMap = {}; + const result = autoPrefix('http://new.com', nsMap); + expect(result).toBe('g0'); + expect(nsMap).toEqual({ 'http://new.com': 'g0' }); + }); + + it('assigns incrementing prefixes based on nsMap size', () => { + const nsMap = { 'http://one.com': 'g0', 'http://two.com': 'g1' }; + const result = autoPrefix('http://three.com', nsMap); + expect(result).toBe('g2'); + expect(nsMap).toEqual({ + 'http://one.com': 'g0', + 'http://two.com': 'g1', + 'http://three.com': 'g2', + }); + }); + + it('does not overwrite existing mapping for different tns', () => { + const nsMap = { 'http://foo.com': 'g0' }; + autoPrefix('http://bar.com', nsMap); + expect(nsMap).toHaveProperty('http://foo.com', 'g0'); + expect(nsMap).toHaveProperty('http://bar.com', 'g1'); + }); +}); diff --git a/packages/ooxml-inspector/generator/src/builder/collect-elements.js b/packages/ooxml-inspector/generator/src/builder/collect-elements.js new file mode 100644 index 0000000000..ce6b8db02c --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/collect-elements.js @@ -0,0 +1,61 @@ +import { arr } from './index.js'; + +/** @type {number} */ +const MAX_XSD_DEPTH = 10; + +/** + * Recursively collect elements from a given node. Most nodes seem to max out around 7 levels + * so 10 seems like a sufficient max. + * + * @param {Object} node - The XML node to collect elements from. + * @param {string} tns - The target namespace. + * @param {string} prefix - The namespace prefix. + * @param {Map} elements - The map to collect elements. + * @param {Map} elementRefs - The map to collect element references. + * @param {number} depth - The current depth in the XML structure. + */ +export function collectElements(node, tns, prefix, elements, elementRefs, depth = 0) { + if (!node || depth > MAX_XSD_DEPTH) return; + + // Direct elements + const els = arr(node['xs:element']).concat(arr(node['xsd:element'])); + for (const el of els) { + if (el.name) { + const key = `${tns}::${el.name}`; + if (!elements.has(key)) { + elements.set(key, { tns, prefix, name: el.name, el }); + } + } else if (el.ref) { + // Track element reference for later resolution + elementRefs.set(el.ref, { tns, prefix }); + } + } + + // Recurse into sequences, choices, alls + const containers = [] + .concat(arr(node['xs:sequence']), arr(node['xsd:sequence'])) + .concat(arr(node['xs:choice']), arr(node['xsd:choice'])) + .concat(arr(node['xs:all']), arr(node['xsd:all'])); + + for (const container of containers) { + collectElements(container, tns, prefix, elements, elementRefs, depth + 1); + } + + // Recurse into complex content + const complexContent = node['xs:complexContent'] || node['xsd:complexContent']; + if (complexContent) { + const ext = complexContent['xs:extension'] || complexContent['xsd:extension']; + const res = complexContent['xs:restriction'] || complexContent['xsd:restriction']; + if (ext) collectElements(ext, tns, prefix, elements, elementRefs, depth + 1); + if (res) collectElements(res, tns, prefix, elements, elementRefs, depth + 1); + } + + // Recurse into simple content (might have attributes that are elements) + const simpleContent = node['xs:simpleContent'] || node['xsd:simpleContent']; + if (simpleContent) { + const ext = simpleContent['xs:extension'] || simpleContent['xsd:extension']; + const res = simpleContent['xs:restriction'] || simpleContent['xsd:restriction']; + if (ext) collectElements(ext, tns, prefix, elements, elementRefs, depth + 1); + if (res) collectElements(res, tns, prefix, elements, elementRefs, depth + 1); + } +} diff --git a/packages/ooxml-inspector/generator/src/builder/collect-elements.test.js b/packages/ooxml-inspector/generator/src/builder/collect-elements.test.js new file mode 100644 index 0000000000..8d2efee571 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/collect-elements.test.js @@ -0,0 +1,235 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { collectElements } from './collect-elements.js'; + +vi.mock('./index.js', () => ({ + arr: vi.fn((x) => (Array.isArray(x) ? x : x ? [x] : [])), +})); + +import { arr } from './index.js'; + +const TNS = 'urn:example'; +const PFX = 'ex'; + +let elements; +let elementRefs; + +beforeEach(() => { + vi.clearAllMocks(); + elements = new Map(); + elementRefs = new Map(); +}); + +describe('collectElements', () => { + it('no-ops on falsy node and respects depth guard', () => { + collectElements(null, TNS, PFX, elements, elementRefs, 0); + expect(elements.size).toBe(0); + expect(elementRefs.size).toBe(0); + + collectElements({}, TNS, PFX, elements, elementRefs, 11); // depth > 10 + expect(elements.size).toBe(0); + expect(elementRefs.size).toBe(0); + }); + + it('collects direct named elements (xs:element & xsd:element)', () => { + const node = { + 'xs:element': [{ name: 'Alpha' }], + 'xsd:element': [{ name: 'Beta' }], + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect([...elements.keys()].sort()).toEqual([`${TNS}::Alpha`, `${TNS}::Beta`]); + expect(elements.get(`${TNS}::Alpha`)).toMatchObject({ + tns: TNS, + prefix: PFX, + name: 'Alpha', + }); + expect(elements.get(`${TNS}::Beta`)).toMatchObject({ + tns: TNS, + prefix: PFX, + name: 'Beta', + }); + expect(elementRefs.size).toBe(0); + }); + + it('tracks element refs (xs/xsd) in elementRefs without expanding', () => { + const node = { + 'xs:element': [{ ref: 'a:Gamma' }], + 'xsd:element': [{ ref: 'Delta' }], + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.size).toBe(0); + expect([...elementRefs.keys()].sort()).toEqual(['Delta', 'a:Gamma']); + expect(elementRefs.get('a:Gamma')).toEqual({ tns: TNS, prefix: PFX }); + expect(elementRefs.get('Delta')).toEqual({ tns: TNS, prefix: PFX }); + }); + + it('does not duplicate existing named elements', () => { + const node = { 'xs:element': [{ name: 'Alpha' }, { name: 'Alpha' }] }; + collectElements(node, TNS, PFX, elements, elementRefs); + expect(elements.size).toBe(1); + expect(elements.has(`${TNS}::Alpha`)).toBe(true); + }); + + it('recurses into sequence/choice/all (xs & xsd variants)', () => { + const node = { + 'xs:sequence': { + 'xsd:element': [{ name: 'SeqChild' }], + 'xs:choice': { + 'xs:element': [{ name: 'ChoiceChild' }], + }, + 'xsd:all': { + 'xsd:element': [{ name: 'AllChild' }], + }, + }, + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.has(`${TNS}::SeqChild`)).toBe(true); + expect(elements.has(`${TNS}::ChoiceChild`)).toBe(true); + expect(elements.has(`${TNS}::AllChild`)).toBe(true); + }); + + it('recurses through complexContent extension and restriction (xs/xsd)', () => { + const node = { + 'xs:complexContent': { + 'xs:extension': { + 'xs:sequence': { 'xs:element': [{ name: 'FromExtension' }] }, + }, + 'xsd:restriction': { + 'xsd:choice': { 'xsd:element': [{ name: 'FromRestriction' }] }, + }, + }, + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.has(`${TNS}::FromExtension`)).toBe(true); + expect(elements.has(`${TNS}::FromRestriction`)).toBe(true); + }); + + it('recurses through simpleContent extension and restriction (xs/xsd)', () => { + const node = { + 'xsd:simpleContent': { + 'xsd:extension': { + 'xs:all': { 'xsd:element': [{ name: 'SCFromExt' }] }, + }, + 'xs:restriction': { + 'xs:sequence': { 'xs:element': [{ name: 'SCFromRes' }] }, + }, + }, + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.has(`${TNS}::SCFromExt`)).toBe(true); + expect(elements.has(`${TNS}::SCFromRes`)).toBe(true); + }); + + it('depth guard includes items at depth 10 but prunes deeper', () => { + // Build nested sequences; place elements at depth 10 and 11 + const makeDeep = (d) => (d === 0 ? {} : { 'xs:sequence': makeDeep(d - 1) }); + const deep = makeDeep(12); + + // Insert at depth 10 and 11 + let cursor = deep; + for (let i = 0; i < 10; i++) cursor = cursor['xs:sequence']; + cursor['xs:element'] = [{ name: 'At10' }]; + cursor = deep; + for (let i = 0; i < 11; i++) cursor = cursor['xs:sequence']; + cursor['xs:element'] = [{ name: 'At11' }]; + + collectElements(deep, TNS, PFX, elements, elementRefs); + + expect(elements.has(`${TNS}::At10`)).toBe(true); // allowed + expect(elements.has(`${TNS}::At11`)).toBe(false); // pruned + }); + + it('uses arr() to normalize singletons and arrays', () => { + const node = { + 'xs:element': { name: 'Solo' }, // singleton + 'xsd:sequence': { 'xs:element': { name: 'NestedSolo' } }, // singleton nested + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(arr).toHaveBeenCalled(); // sanity: we used arr + expect(elements.has(`${TNS}::Solo`)).toBe(true); + expect(elements.has(`${TNS}::NestedSolo`)).toBe(true); + }); + + it('handles complexContent with only extension (no restriction)', () => { + const node = { + 'xs:complexContent': { + 'xs:extension': { + 'xs:sequence': { 'xs:element': [{ name: 'OnlyExtension' }] }, + }, + // No restriction here - this covers the "false" branch of if (res) + }, + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.has(`${TNS}::OnlyExtension`)).toBe(true); + }); + + it('handles complexContent with only restriction (no extension)', () => { + const node = { + 'xs:complexContent': { + 'xsd:restriction': { + 'xsd:choice': { 'xsd:element': [{ name: 'OnlyRestriction' }] }, + }, + // No extension here - this covers the "false" branch of if (ext) + }, + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.has(`${TNS}::OnlyRestriction`)).toBe(true); + }); + + it('handles simpleContent with only extension (no restriction)', () => { + const node = { + 'xsd:simpleContent': { + 'xsd:extension': { + 'xs:all': { 'xsd:element': [{ name: 'SCOnlyExt' }] }, + }, + // No restriction here - this covers the "false" branch of if (res) in simpleContent + }, + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.has(`${TNS}::SCOnlyExt`)).toBe(true); + }); + + it('handles simpleContent with only restriction (no extension)', () => { + const node = { + 'xsd:simpleContent': { + 'xs:restriction': { + 'xs:sequence': { 'xs:element': [{ name: 'SCOnlyRes' }] }, + }, + // No extension here - this covers the "false" branch of if (ext) in simpleContent + }, + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.has(`${TNS}::SCOnlyRes`)).toBe(true); + }); + + it('handles complexContent with neither extension nor restriction', () => { + const node = { + 'xs:complexContent': { + // Neither extension nor restriction - covers both false branches + }, + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.size).toBe(0); // No elements should be added + }); + + it('handles simpleContent with neither extension nor restriction', () => { + const node = { + 'xsd:simpleContent': { + // Neither extension nor restriction - covers both false branches + }, + }; + collectElements(node, TNS, PFX, elements, elementRefs); + + expect(elements.size).toBe(0); // No elements should be added + }); +}); diff --git a/packages/ooxml-inspector/generator/src/builder/expand-content.js b/packages/ooxml-inspector/generator/src/builder/expand-content.js new file mode 100644 index 0000000000..3353341fc9 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/expand-content.js @@ -0,0 +1,115 @@ +import { arr, autoPrefix } from './index.js'; + +/** + * Collect elements from a given node. + * Recursively collect xs:element nodes from sequences/choices/alls/groups + * Also collects element definitions found along the way + * @param {Object} node - The XML node to collect elements from. + * @param {Array} outEls - The output array to collect elements into. + * @param {string} contextTns - The current target namespace. + * @param {number} depth - The current depth in the XML structure. + * @param {Map} elementsMap - A map of known elements. + * @param {Record} nsMap - A map of namespace prefixes. + * @param {Map} groups - A map of group definitions. + * @returns {void} + */ +export function expandContent(node, outEls, contextTns, depth = 0, elementsMap, nsMap, groups) { + if (!node || depth > 10) return; // prevent infinite recursion + + // Direct elements + const els = arr(node['xs:element']).concat(arr(node['xsd:element'])); + for (const e of els) { + outEls.push({ ...e, _contextTns: contextTns }); + + // Also track this as a known element if it has a name + if (e.name) { + const elKey = `${contextTns}::${e.name}`; + const elPrefix = nsMap[contextTns] || autoPrefix(contextTns, nsMap); + if (!elementsMap.has(elKey)) { + elementsMap.set(elKey, { + tns: contextTns, + prefix: elPrefix, + name: e.name, + el: e, + }); + } + } else if (e.ref) { + // Track element reference + let refTns, refName; + if (e.ref.includes(':')) { + const [refPrefix, local] = e.ref.split(':'); + refName = local; + refTns = Object.entries(nsMap).find(([, v]) => v === refPrefix)?.[0]; + } else { + refName = e.ref; + refTns = contextTns; + } + + if (refTns && refName) { + const elKey = `${refTns}::${refName}`; + const elPrefix = nsMap[refTns] || autoPrefix(refTns, nsMap); + if (!elementsMap.has(elKey)) { + elementsMap.set(elKey, { + tns: refTns, + prefix: elPrefix, + name: refName, + el: { name: refName, type: `CT_${refName.charAt(0).toUpperCase() + refName.slice(1)}` }, + }); + } + } + } + } + + // Nested content models + const nests = [] + .concat(arr(node['xs:sequence']), arr(node['xsd:sequence'])) + .concat(arr(node['xs:choice']), arr(node['xsd:choice'])) + .concat(arr(node['xs:all']), arr(node['xsd:all'])); + + for (const n of nests) { + expandContent(n, outEls, contextTns, depth + 1, elementsMap, nsMap, groups); + } + + // Group references + const gs = arr(node['xs:group']).concat(arr(node['xsd:group'])); + for (const g of gs) { + if (g.name) { + // Inline group definition + const groupContent = + g['xs:sequence'] || g['xs:choice'] || g['xs:all'] || g['xsd:sequence'] || g['xsd:choice'] || g['xsd:all']; + if (groupContent) { + expandContent(groupContent, outEls, contextTns, depth + 1, elementsMap, nsMap, groups); + } + continue; + } + + const ref = g.ref; + if (!ref) continue; + + let groupTns, localName; + if (ref.includes(':')) { + const [pfx, local] = ref.split(':'); + localName = local; + groupTns = Object.entries(nsMap).find(([, v]) => v === pfx)?.[0]; + } else { + localName = ref; + groupTns = contextTns; + } + + if (!groupTns) continue; + + const groupDef = groups.get(`${groupTns}::${localName}`); + if (!groupDef) continue; + + const groupContent = + groupDef['xs:sequence'] || + groupDef['xs:choice'] || + groupDef['xs:all'] || + groupDef['xsd:sequence'] || + groupDef['xsd:choice'] || + groupDef['xsd:all']; + if (groupContent) { + expandContent(groupContent, outEls, groupTns, depth + 1, elementsMap, nsMap, groups); + } + } +} diff --git a/packages/ooxml-inspector/generator/src/builder/expand-content.test.js b/packages/ooxml-inspector/generator/src/builder/expand-content.test.js new file mode 100644 index 0000000000..87ad8a248e --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/expand-content.test.js @@ -0,0 +1,283 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { expandContent } from './expand-content.js'; + +vi.mock('./index.js', () => { + return { + arr: vi.fn((x) => (Array.isArray(x) ? x : x ? [x] : [])), + autoPrefix: vi.fn(() => 'gen'), + }; +}); + +import { arr, autoPrefix } from './index.js'; + +const TNS_A = 'urn:a'; +const TNS_B = 'urn:b'; + +let nsMap; +let elementsMap; +let groups; + +beforeEach(() => { + vi.clearAllMocks(); + nsMap = { + [TNS_A]: 'a', + [TNS_B]: 'b', + }; + elementsMap = new Map(); + groups = new Map(); +}); + +describe('expandContent', () => { + it('no-ops on falsy node and respects depth guard', () => { + const outEls = []; + expandContent(null, outEls, TNS_A, 0, elementsMap, nsMap, groups); + expect(outEls).toEqual([]); + + expandContent({}, outEls, TNS_A, 11, elementsMap, nsMap, groups); // depth > 10 + expect(outEls).toEqual([]); + }); + + it('collects direct elements (xs:element & xsd:element) and stamps _contextTns', () => { + const outEls = []; + const node = { + 'xs:element': [{ name: 'Alpha' }], + 'xsd:element': [{ ref: 'b:Beta' }], + }; + + expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups); + + // outEls should contain both, with _contextTns + expect(outEls).toHaveLength(2); + expect(outEls[0]).toMatchObject({ name: 'Alpha', _contextTns: TNS_A }); + expect(outEls[1]).toMatchObject({ ref: 'b:Beta', _contextTns: TNS_A }); + + // elementsMap should have a record for named element Alpha in context A + const alphaKey = `${TNS_A}::Alpha`; + expect(elementsMap.get(alphaKey)).toMatchObject({ + tns: TNS_A, + prefix: 'a', + name: 'Alpha', + }); + + // and for referenced element Beta (resolved to TNS_B, local 'Beta') + const betaKey = `${TNS_B}::Beta`; + expect(elementsMap.get(betaKey)).toMatchObject({ + tns: TNS_B, + prefix: 'b', + name: 'Beta', + }); + + // autoPrefix not needed here (both namespaces mapped) + expect(autoPrefix).not.toHaveBeenCalled(); + }); + + it('uses autoPrefix for named element when contextTns is unmapped', () => { + const outEls = []; + autoPrefix.mockReturnValueOnce('ap'); // deterministic + const node = { 'xs:element': [{ name: 'Gamma' }] }; + + expandContent(node, outEls, 'urn:unmapped', 0, elementsMap, nsMap, groups); + + // one element collected + expect(outEls).toHaveLength(1); + expect(outEls[0]).toMatchObject({ name: 'Gamma', _contextTns: 'urn:unmapped' }); + + // elementsMap entry uses autoPrefix result + const key = `urn:unmapped::Gamma`; + expect(elementsMap.get(key)).toMatchObject({ + tns: 'urn:unmapped', + prefix: 'ap', + name: 'Gamma', + }); + + expect(autoPrefix).toHaveBeenCalledWith('urn:unmapped', nsMap); + }); + + it('uses autoPrefix for referenced element when ref TNS is unmapped', () => { + const outEls = []; + // Arrange: nsMap doesn’t have a prefix for this ref’s TNS + const UNMAPPED = 'urn:zzz'; + nsMap[UNMAPPED] = undefined; // ensure missing + autoPrefix.mockReturnValueOnce('zp'); + + // e.ref without prefix -> uses contextTns (UNMAPPED) in this case + const node = { 'xs:element': [{ ref: 'Zed' }] }; + + expandContent(node, outEls, UNMAPPED, 0, elementsMap, nsMap, groups); + + const key = `${UNMAPPED}::Zed`; + expect(elementsMap.get(key)).toMatchObject({ + tns: UNMAPPED, + prefix: 'zp', + name: 'Zed', + el: expect.objectContaining({ name: 'Zed' }), + }); + expect(autoPrefix).toHaveBeenCalledWith(UNMAPPED, nsMap); + }); + + it('recurses into nested content models (sequence/choice/all, xs/xsd)', () => { + const outEls = []; + const node = { + 'xs:sequence': { + 'xsd:element': [{ name: 'SeqEl' }], + 'xs:choice': { + 'xs:element': [{ name: 'ChoiceEl' }], + }, + 'xsd:all': { + 'xsd:element': [{ name: 'AllEl' }], + }, + }, + }; + + expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups); + + const names = outEls.map((e) => e.name || e.ref); + expect(names).toEqual(expect.arrayContaining(['SeqEl', 'ChoiceEl', 'AllEl'])); + + // all should be recorded into elementsMap too + expect(elementsMap.has(`${TNS_A}::SeqEl`)).toBe(true); + expect(elementsMap.has(`${TNS_A}::ChoiceEl`)).toBe(true); + expect(elementsMap.has(`${TNS_A}::AllEl`)).toBe(true); + }); + + it('handles inline group definitions (xs:group with name + inner sequence/choice/all)', () => { + const outEls = []; + const node = { + 'xs:group': [ + { + name: 'InlineGroup', + 'xs:choice': { 'xs:element': [{ name: 'InlineEl' }] }, + }, + ], + }; + + expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups); + + const names = outEls.map((e) => e.name || e.ref); + expect(names).toContain('InlineEl'); + expect(elementsMap.has(`${TNS_A}::InlineEl`)).toBe(true); + }); + + it('expands group references by local name using current context TNS', () => { + const outEls = []; + // groups map stores definitions keyed by `${tns}::${name}` + groups.set(`${TNS_A}::MyGroup`, { + 'xs:sequence': { 'xs:element': [{ name: 'GEl' }] }, + }); + + const node = { + 'xs:group': [{ ref: 'MyGroup' }], + }; + + expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups); + + const names = outEls.map((e) => e.name || e.ref); + expect(names).toContain('GEl'); + expect(elementsMap.has(`${TNS_A}::GEl`)).toBe(true); + }); + + it('expands group references with prefix using nsMap to resolve TNS', () => { + const outEls = []; + groups.set(`${TNS_B}::OtherGroup`, { + 'xsd:all': { 'xsd:element': [{ name: 'OtherEl' }] }, + }); + + const node = { + 'xsd:group': [{ ref: 'b:OtherGroup' }], + }; + + expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups); + + const names = outEls.map((e) => e.name || e.ref); + expect(names).toContain('OtherEl'); + expect(elementsMap.has(`${TNS_B}::OtherEl`)).toBe(true); + }); + + it('does nothing for unknown group prefix or missing group definition', () => { + const outEls = []; + const node = { + 'xs:group': [{ ref: 'z:Nope' }, { ref: 'MissingGroup' }], + }; + + expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups); + expect(outEls).toHaveLength(0); + expect(elementsMap.size).toBe(0); + }); + + it('depth guard prevents collecting too-deep nested elements', () => { + const makeDeep = (depth) => + depth === 0 + ? { 'xs:element': [{ name: 'TooDeep' }] } // will land deeper than the guard + : { 'xs:sequence': makeDeep(depth - 1) }; + + // Build 12 levels of nested sequences; the base element is beyond depth 10 + const deep = makeDeep(12); + + // Insert an element exactly at depth 10 so it should be included + let cursor = deep; + for (let i = 0; i < 10; i++) cursor = cursor['xs:sequence']; + cursor['xs:element'] = [{ name: 'AtDepth10' }]; + + const outEls = []; + expandContent(deep, outEls, TNS_A, 0, elementsMap, nsMap, groups); + + const names = outEls.map((e) => e.name || e.ref); + expect(names).toContain('AtDepth10'); // depth 10 is allowed + expect(names).not.toContain('TooDeep'); // pruned at depth > 10 + }); + + it('handles element ref with unknown prefix (refTns becomes undefined)', () => { + const outEls = []; + const node = { + 'xs:element': [{ ref: 'unknown:Element' }], // prefix not in nsMap + }; + + expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups); + + // Element should still be added to outEls but not to elementsMap + expect(outEls).toHaveLength(1); + expect(outEls[0]).toMatchObject({ ref: 'unknown:Element', _contextTns: TNS_A }); + + // No entry should be added to elementsMap because refTns is undefined + expect(elementsMap.size).toBe(0); + }); + + it('handles group definition with no content models', () => { + const outEls = []; + + // Group exists but has no sequence/choice/all content + groups.set(`${TNS_A}::EmptyGroup`, { + // No xs:sequence, xs:choice, xs:all, etc. + someOtherProperty: 'value', + }); + + const node = { + 'xs:group': [{ ref: 'EmptyGroup' }], + }; + + expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups); + + // Should find the group but do nothing since it has no content + expect(outEls).toHaveLength(0); + expect(elementsMap.size).toBe(0); + }); + + it('handles inline group definition with no content models', () => { + const outEls = []; + const node = { + 'xs:group': [ + { + name: 'InlineEmptyGroup', + // No xs:sequence, xs:choice, xs:all content + someAttribute: 'value', + }, + ], + }; + + expandContent(node, outEls, TNS_A, 0, elementsMap, nsMap, groups); + + // Should process the inline group but do nothing since it has no content + expect(outEls).toHaveLength(0); + expect(elementsMap.size).toBe(0); + }); +}); diff --git a/packages/ooxml-inspector/generator/src/builder/index.js b/packages/ooxml-inspector/generator/src/builder/index.js new file mode 100644 index 0000000000..67421c6b83 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/index.js @@ -0,0 +1,6 @@ +export * from './collect-elements.js'; +export * from './autoprefix.js'; +export * from './resolve-child-q-name.js'; +export * from './xsd-helpers.js'; +export * from './resolve-type.js'; +export * from './expand-content.js'; diff --git a/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.js b/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.js new file mode 100644 index 0000000000..df10ff90bc --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.js @@ -0,0 +1,32 @@ +import { autoPrefix, qn } from './index.js'; + +/** + * Resolve the qualified name of a child element. + * @param {Object} e - The element to resolve. + * @param {string} contextTns - The current target namespace. + * @param {Object} nsMap - The namespace map. + * @returns {string|null} - The resolved qualified name or null if not found. + */ +export function resolveChildQName(e, contextTns, nsMap) { + if (e.ref) { + // Element reference + if (e.ref.includes(':')) { + const [pfx, local] = e.ref.split(':'); + const targetTns = Object.entries(nsMap).find(([, v]) => v === pfx)?.[0]; + if (!targetTns) return null; + return qn(nsMap[targetTns], local); + } else { + // No prefix, assume same namespace + return qn(nsMap[contextTns] || 'unknown', e.ref); + } + } + + if (e.name) { + // Inline element - use context TNS or the element's own _contextTns + const elementTns = e._contextTns || contextTns; + const prefix = nsMap[elementTns] || autoPrefix(elementTns, nsMap); + return qn(prefix, e.name); + } + + return null; +} diff --git a/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.test.js b/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.test.js new file mode 100644 index 0000000000..aaf7e7371e --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/resolve-child-q-name.test.js @@ -0,0 +1,97 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { resolveChildQName } from './resolve-child-q-name.js'; + +vi.mock('./index.js', () => { + return { + qn: vi.fn((pfx, local) => `${pfx}:${local}`), + autoPrefix: vi.fn(() => 'auto'), + }; +}); + +import { qn, autoPrefix } from './index.js'; + +const TNS_A = 'urn:a'; +const TNS_B = 'urn:b'; +const TNS_C = 'urn:c'; + +let nsMap; + +beforeEach(() => { + vi.clearAllMocks(); + nsMap = { + [TNS_A]: 'a', + [TNS_B]: 'b', + // note: TNS_C intentionally not present in default map + }; +}); + +describe('resolveChildQName', () => { + it('returns null when neither ref nor name is provided', () => { + expect(resolveChildQName({}, TNS_A, nsMap)).toBeNull(); + }); + + describe('when e.ref is present', () => { + it('resolves prefixed ref using nsMap -> qn(prefix, local)', () => { + const e = { ref: 'b:Child' }; // prefix "b" -> TNS_B + const out = resolveChildQName(e, TNS_A, nsMap); + expect(out).toBe('b:Child'); + expect(qn).toHaveBeenCalledWith('b', 'Child'); + expect(autoPrefix).not.toHaveBeenCalled(); + }); + + it('returns null for unknown prefix', () => { + const e = { ref: 'z:Foo' }; // no matching prefix in nsMap + const out = resolveChildQName(e, TNS_A, nsMap); + expect(out).toBeNull(); + expect(qn).not.toHaveBeenCalled(); + expect(autoPrefix).not.toHaveBeenCalled(); + }); + + it('uses context namespace when ref has no prefix', () => { + const e = { ref: 'LocalName' }; + const out = resolveChildQName(e, TNS_A, nsMap); + expect(out).toBe('a:LocalName'); // nsMap[TNS_A] === 'a' + expect(qn).toHaveBeenCalledWith('a', 'LocalName'); + expect(autoPrefix).not.toHaveBeenCalled(); + }); + + it('falls back to "unknown" prefix when contextTns is unmapped', () => { + const e = { ref: 'Thing' }; + const out = resolveChildQName(e, TNS_C, nsMap); // TNS_C not in nsMap + expect(out).toBe('unknown:Thing'); + expect(qn).toHaveBeenCalledWith('unknown', 'Thing'); + expect(autoPrefix).not.toHaveBeenCalled(); + }); + }); + + describe('when e.name is present (inline element)', () => { + it('uses contextTns mapping when _contextTns is not provided', () => { + const e = { name: 'Inline' }; + const out = resolveChildQName(e, TNS_A, nsMap); + expect(out).toBe('a:Inline'); + expect(qn).toHaveBeenCalledWith('a', 'Inline'); + expect(autoPrefix).not.toHaveBeenCalled(); + }); + + it('uses element _contextTns mapping when present', () => { + const e = { name: 'Inline', _contextTns: TNS_B }; + const out = resolveChildQName(e, TNS_A, nsMap); + expect(out).toBe('b:Inline'); + expect(qn).toHaveBeenCalledWith('b', 'Inline'); + expect(autoPrefix).not.toHaveBeenCalled(); + }); + + it('calls autoPrefix when _contextTns is unmapped and uses its returned prefix', () => { + // make autoPrefix return a deterministic value + autoPrefix.mockReturnValueOnce('gen'); + + const e = { name: 'Inline', _contextTns: TNS_C }; // TNS_C not in nsMap + const out = resolveChildQName(e, TNS_A, nsMap); + + expect(autoPrefix).toHaveBeenCalledTimes(1); + expect(autoPrefix).toHaveBeenCalledWith(TNS_C, nsMap); + expect(out).toBe('gen:Inline'); + expect(qn).toHaveBeenCalledWith('gen', 'Inline'); + }); + }); +}); diff --git a/packages/ooxml-inspector/generator/src/builder/resolve-type.js b/packages/ooxml-inspector/generator/src/builder/resolve-type.js new file mode 100644 index 0000000000..f19db6d5d2 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/resolve-type.js @@ -0,0 +1,52 @@ +/** + * Resolves a complex type by its name. + * @param {string} typeName - The name of the complex type. + * @param {string} contextTns - The current target namespace. + * @param {Object} nsMap - The namespace map. + * @param {Object} complexTypes - The map of complex types. + * @param {Object} simpleTypes - The map of simple types. + * @returns {Object|null} - The resolved complex type or null if not found. + */ +export function resolveType(typeName, contextTns, nsMap, complexTypes, simpleTypes) { + if (!typeName) return null; + + let targetTns, localName; + if (typeName.includes(':')) { + const [pfx, local] = typeName.split(':'); + localName = local; + + // Handle XSD built-in types - these are simple types, not complex types + if (pfx === 'xsd' || pfx === 'xs') { + return null; // XSD built-in types don't have child elements + } + + // Find TNS from prefix - check the context schema's namespace declarations + targetTns = Object.entries(nsMap).find(([, v]) => v === pfx)?.[0]; + if (!targetTns) { + console.warn(`Unknown prefix '${pfx}' in type: ${typeName}`); + return null; + } + } else { + // No prefix, use context TNS + localName = typeName; + targetTns = contextTns; + } + + const key = `${targetTns}::${localName}`; + const resolved = complexTypes.get(key); + + if (!resolved) { + // Check if it's a simple type (which we don't need to resolve for child elements) + if (simpleTypes.has(key)) { + // This is a simple type - no warning needed + return null; + } + + // Only warn if it's not a known simple type or XSD type + if (!typeName.startsWith('xsd:') && !typeName.startsWith('xs:')) { + console.warn(`Could not resolve complex type: ${typeName} in context ${contextTns}`); + } + } + + return resolved || null; +} diff --git a/packages/ooxml-inspector/generator/src/builder/resolve-type.test.js b/packages/ooxml-inspector/generator/src/builder/resolve-type.test.js new file mode 100644 index 0000000000..ae3925cbb2 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/resolve-type.test.js @@ -0,0 +1,100 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; +import { resolveType } from './index.js'; + +const TNS_A = 'http://example.com/a'; +const TNS_B = 'http://example.com/b'; + +/** + * nsMap is expected to be { [tns]: prefix } + * so Object.entries(nsMap).find(([, v]) => v === pfx)?.[0] yields the TNS. + */ +const nsMap = { + [TNS_A]: 'a', + [TNS_B]: 'b', +}; + +let complexTypes; +let simpleTypes; + +beforeEach(() => { + complexTypes = new Map(); + simpleTypes = new Map(); + vi.restoreAllMocks(); +}); + +describe('resolveType', () => { + it('returns null for falsy typeName', () => { + expect(resolveType('', TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull(); + expect(resolveType(null, TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull(); + expect(resolveType(undefined, TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull(); + }); + + it('returns null for built-in XSD types (xs: / xsd:) without warnings', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + expect(resolveType('xs:string', TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull(); + expect(resolveType('xsd:int', TNS_A, nsMap, complexTypes, simpleTypes)).toBeNull(); + expect(warnSpy).not.toHaveBeenCalled(); + }); + + it('resolves unprefixed name using contextTns', () => { + const key = `${TNS_A}::Foo`; + const resolved = { name: 'FooCT' }; + complexTypes.set(key, resolved); + + const out = resolveType('Foo', TNS_A, nsMap, complexTypes, simpleTypes); + expect(out).toBe(resolved); + }); + + it('resolves prefixed name using nsMap', () => { + const key = `${TNS_B}::Bar`; + const resolved = { name: 'BarCT' }; + complexTypes.set(key, resolved); + + const out = resolveType('b:Bar', TNS_A, nsMap, complexTypes, simpleTypes); + expect(out).toBe(resolved); + }); + + it('returns null and warns on unknown prefix', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const out = resolveType('z:Thing', TNS_A, nsMap, complexTypes, simpleTypes); + expect(out).toBeNull(); + expect(warnSpy).toHaveBeenCalledTimes(1); + expect(warnSpy.mock.calls[0][0]).toMatch(/Unknown prefix 'z'/); + }); + + it('returns null (no warning) when complex type missing but simple type exists', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const key = `${TNS_A}::SimpleOne`; + simpleTypes.set(key, { kind: 'simple' }); + + const out = resolveType('SimpleOne', TNS_A, nsMap, complexTypes, simpleTypes); + expect(out).toBeNull(); + expect(warnSpy).not.toHaveBeenCalled(); + }); + + it('warns when not found in complexTypes and not a simple type (non-XSD)', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const out = resolveType('MissingType', TNS_A, nsMap, complexTypes, simpleTypes); + expect(out).toBeNull(); + expect(warnSpy).toHaveBeenCalledTimes(1); + expect(warnSpy.mock.calls[0][0]).toMatch(/Could not resolve complex type: MissingType/); + expect(warnSpy.mock.calls[0][0]).toMatch(TNS_A); + }); + + it('does not warn when not found but the name is an XSD built-in (defensive check)', () => { + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + // Even if someone passed "xs:unknownBuiltin", function guards against warning due to xs/xsd check. + const out = resolveType('xs:unknownBuiltin', TNS_A, nsMap, complexTypes, simpleTypes); + expect(out).toBeNull(); + expect(warnSpy).not.toHaveBeenCalled(); + }); + + it('constructs the key as `${targetTns}::${localName}`', () => { + const key = `${TNS_B}::Baz`; + const resolved = { id: 123, name: 'BazCT' }; + complexTypes.set(key, resolved); + + const out = resolveType('b:Baz', TNS_A, nsMap, complexTypes, simpleTypes); + expect(out).toEqual(resolved); + }); +}); diff --git a/packages/ooxml-inspector/generator/src/builder/xsd-helpers.js b/packages/ooxml-inspector/generator/src/builder/xsd-helpers.js new file mode 100644 index 0000000000..c45da10243 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/xsd-helpers.js @@ -0,0 +1,62 @@ +import { XMLParser } from 'fast-xml-parser'; + +/** XML parser instance for parsing XSD files. */ +export const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '' }); + +/** + * Converts a value to an array. + * @param {any} x - The value to convert. + * @returns {Array} - The converted array. + */ +export const arr = (x) => (Array.isArray(x) ? x : x ? [x] : []); + +/** + * Generates a qualified name (QName) from a prefix and local name. + * @param {string} pfx - The namespace prefix. + * @param {string} local - The local name. + * @returns {string} - The qualified name. + */ +export const qn = (pfx, local) => `${pfx}:${local}`; + +/** + * Resolves an inline complex type definition. + * @param {Object} el - The element to resolve. + * @returns {Object|null} - The resolved complex type or null if not found. + */ +export function inlineCT(el) { + return el['xs:complexType'] || el['xsd:complexType'] || null; +} + +/** + * Get the content model for a complex type. + * @param {Object} complexType - The complex type definition. + * @returns {Object|null} - The content model or null if not found. + */ +export function contentRoot(complexType) { + // Check for complex content extensions first + const complexContent = complexType['xs:complexContent'] || complexType['xsd:complexContent']; + if (complexContent) { + const ext = complexContent['xs:extension'] || complexContent['xsd:extension']; + if (ext) { + return ( + ext['xs:sequence'] || + ext['xs:choice'] || + ext['xs:all'] || + ext['xsd:sequence'] || + ext['xsd:choice'] || + ext['xsd:all'] + ); + } + } + + // Direct content model + return ( + complexType['xs:sequence'] || + complexType['xs:choice'] || + complexType['xs:all'] || + complexType['xsd:sequence'] || + complexType['xsd:choice'] || + complexType['xsd:all'] || + null + ); +} diff --git a/packages/ooxml-inspector/generator/src/builder/xsd-helpers.test.js b/packages/ooxml-inspector/generator/src/builder/xsd-helpers.test.js new file mode 100644 index 0000000000..d2413edd29 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/builder/xsd-helpers.test.js @@ -0,0 +1,137 @@ +import { describe, it, expect } from 'vitest'; +import { parser, arr, qn, inlineCT, contentRoot } from './index.js'; + +describe('parser (fast-xml-parser) config', () => { + it('parses attributes (ignoreAttributes=false) with empty attributeNamePrefix', () => { + const xml = `text`; + const out = parser.parse(xml); + + expect(out.root.id).toBe('42'); + expect(out.root.child).toBe('text'); + }); + + it('handles multiple attributes without prefix collisions', () => { + const xml = ``; + const out = parser.parse(xml); + expect(out.el.a).toBe('1'); + expect(out.el.b).toBe('2'); + expect(out.el.c).toBe('3'); + }); +}); + +describe('arr()', () => { + it('returns arrays unchanged (same reference)', () => { + const input = [1, 2]; + expect(arr(input)).toBe(input); + }); + + it('wraps truthy non-arrays into an array', () => { + expect(arr('x')).toEqual(['x']); + expect(arr({ a: 1 })).toEqual([{ a: 1 }]); + expect(arr(true)).toEqual([true]); + }); + + it('returns [] for falsy values (null/undefined/0/empty string)', () => { + expect(arr(null)).toEqual([]); + expect(arr(undefined)).toEqual([]); + expect(arr(0)).toEqual([]); + expect(arr('')).toEqual([]); + }); +}); + +describe('qn()', () => { + it('joins prefix and local with a colon', () => { + expect(qn('w', 'p')).toBe('w:p'); + expect(qn('xs', 'sequence')).toBe('xs:sequence'); + }); +}); + +describe('inlineCT()', () => { + it('returns xs:complexType when present', () => { + const el = { 'xs:complexType': { name: 'CT_Something' } }; + expect(inlineCT(el)).toEqual({ name: 'CT_Something' }); + }); + + it('returns xsd:complexType when present', () => { + const el = { 'xsd:complexType': { name: 'CT_Other' } }; + expect(inlineCT(el)).toEqual({ name: 'CT_Other' }); + }); + + it('returns null when not present', () => { + const el = { foo: 'bar' }; + expect(inlineCT(el)).toBeNull(); + }); +}); + +describe('contentRoot()', () => { + it('picks direct xs:sequence/xs:choice/xs:all', () => { + const withSeq = { 'xs:sequence': { tag: 'seq' } }; + const withChoice = { 'xs:choice': { tag: 'choice' } }; + const withAll = { 'xs:all': { tag: 'all' } }; + + expect(contentRoot(withSeq)).toEqual({ tag: 'seq' }); + expect(contentRoot(withChoice)).toEqual({ tag: 'choice' }); + expect(contentRoot(withAll)).toEqual({ tag: 'all' }); + }); + + it('picks direct xsd:sequence/xsd:choice/xsd:all', () => { + const withSeq = { 'xsd:sequence': { tag: 'seq' } }; + const withChoice = { 'xsd:choice': { tag: 'choice' } }; + const withAll = { 'xsd:all': { tag: 'all' } }; + + expect(contentRoot(withSeq)).toEqual({ tag: 'seq' }); + expect(contentRoot(withChoice)).toEqual({ tag: 'choice' }); + expect(contentRoot(withAll)).toEqual({ tag: 'all' }); + }); + + it('resolves through complexContent/extension (xs:*)', () => { + const ct = { + 'xs:complexContent': { + 'xs:extension': { + 'xs:sequence': { tag: 'ext-seq' }, + }, + }, + }; + expect(contentRoot(ct)).toEqual({ tag: 'ext-seq' }); + }); + + it('resolves through complexContent/extension (xsd:*)', () => { + const ct = { + 'xsd:complexContent': { + 'xsd:extension': { + 'xsd:choice': { tag: 'ext-choice' }, + }, + }, + }; + expect(contentRoot(ct)).toEqual({ tag: 'ext-choice' }); + }); + + it('resolves xsd:all through complexContent/extension', () => { + const ct = { + 'xsd:complexContent': { + 'xsd:extension': { + 'xsd:all': { tag: 'ext-all' }, + }, + }, + }; + expect(contentRoot(ct)).toEqual({ tag: 'ext-all' }); + }); + + it('prefers extension child order: sequence > choice > all', () => { + const ct = { + 'xs:complexContent': { + 'xs:extension': { + 'xs:choice': { tag: 'choice' }, + 'xs:sequence': { tag: 'seq' }, // sequence should win + 'xs:all': { tag: 'all' }, + }, + }, + }; + expect(contentRoot(ct)).toEqual({ tag: 'seq' }); + }); + + it('returns null when no content model exists', () => { + const ct = { name: 'NoContent' }; + expect(contentRoot(ct)).toBeNull(); + }); +}); diff --git a/packages/ooxml-inspector/generator/src/constants.js b/packages/ooxml-inspector/generator/src/constants.js new file mode 100644 index 0000000000..d9fd6855f6 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/constants.js @@ -0,0 +1,45 @@ +/** + * Directory containing the XSP files. + */ +export const XSP_DIR = 'specification/OfficeOpenXML-XMLSchema-Transitional'; + +/** + * Map of XML namespace URIs to their corresponding prefixes. + */ +export const NS_MAP = { + 'http://schemas.openxmlformats.org/wordprocessingml/2006/main': 'w', + 'http://schemas.openxmlformats.org/drawingml/2006/main': 'a', + 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing': 'wp', + 'http://schemas.openxmlformats.org/drawingml/2006/chartDrawing': 'cdr', + 'http://schemas.openxmlformats.org/officeDocument/2006/math': 'm', + 'http://schemas.openxmlformats.org/markup-compatibility/2006': 'mc', + 'http://schemas.openxmlformats.org/officeDocument/2006/relationships': 'r', + 'http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes': 's', + 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes': 'vt', + 'http://schemas.openxmlformats.org/presentationml/2006/main': 'p', + 'http://schemas.openxmlformats.org/spreadsheetml/2006/main': 'x', + 'http://www.w3.org/2001/XMLSchema': 'xsd', +}; + +/** + * Set of element names that should be passed through without modification. + */ +export const PASS_THROUGH = new Set([ + 'mc:AlternateContent', + 'w:sdt', + 'w:customXml', + 'w:ins', + 'w:del', + 'w:moveFrom', + 'w:moveTo', + 'w:proofErr', + 'w:permStart', + 'w:permEnd', + 'w:bookmarkStart', + 'w:bookmarkEnd', +]); + +/** + * Set of element names that require extra wrapper elements. + */ +export const EXTRA_WRAPPER_PARENTS = new Set(['w:p', 'w:tc', 'w:body', 'w:document']); diff --git a/packages/ooxml-inspector/generator/src/generator.js b/packages/ooxml-inspector/generator/src/generator.js new file mode 100644 index 0000000000..09441012ad --- /dev/null +++ b/packages/ooxml-inspector/generator/src/generator.js @@ -0,0 +1,18 @@ +import { writeFileSync, mkdirSync } from 'node:fs'; +import { XSP_DIR, buildFromXsdDir } from './index.js'; + +/** + * Run the XML Schema generator. Converts OOXML .xsp definitions to json in dist + */ +export function runGenerator() { + const out = buildFromXsdDir(XSP_DIR); + mkdirSync('dist', { recursive: true }); + writeFileSync('dist/schema.transitional.json', JSON.stringify(out, null, 2)); + console.log('Wrote dist/schema.transitional.json'); + + console.log('\nSample entries:'); + const elements = out.elements; + for (const key of ['w:document', 'w:body', 'w:p', 'w:r', 'w:t', 'w:pPr', 'w:rPr']) { + console.log(`${key}: ${elements[key] ? elements[key].children.length : 'not found'} children`); + } +} diff --git a/packages/ooxml-inspector/generator/src/generator.test.js b/packages/ooxml-inspector/generator/src/generator.test.js new file mode 100644 index 0000000000..4deb434f15 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/generator.test.js @@ -0,0 +1,117 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; + +vi.mock('node:fs', () => { + return { + writeFileSync: vi.fn(), + mkdirSync: vi.fn(), + }; +}); + +// Mock the sibling module that runGenerator imports from +const buildFromXsdDirMock = vi.fn(); +const XSP_DIR_VALUE = '/fake/xsp'; +vi.mock('./index.js', () => ({ + XSP_DIR: XSP_DIR_VALUE, + buildFromXsdDir: buildFromXsdDirMock, +})); + +let runGenerator; +let writeFileSync, mkdirSync; + +beforeEach(async () => { + vi.resetModules(); + + ({ writeFileSync, mkdirSync } = await import('node:fs')); + + // spy on console + vi.spyOn(console, 'log').mockImplementation(() => {}); + + ({ runGenerator } = await import('./generator.js')); +}); + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe('runGenerator', () => { + it('generates schema, writes file, and logs sample entries for present keys', () => { + // Arrange a schema with all the sample keys present + const out = { + elements: { + 'w:document': { children: [], attributes: {} }, + 'w:body': { children: ['w:p'], attributes: {} }, + 'w:p': { children: ['w:r'], attributes: {} }, + 'w:r': { children: ['w:t'], attributes: {} }, + 'w:t': { children: [], attributes: {} }, + 'w:pPr': { children: ['w:spacing'], attributes: {} }, + 'w:rPr': { children: [], attributes: {} }, + }, + }; + buildFromXsdDirMock.mockReturnValue(out); + + // Act + runGenerator(); + + // Assert: buildFromXsdDir called with XSP_DIR + expect(buildFromXsdDirMock).toHaveBeenCalledTimes(1); + expect(buildFromXsdDirMock).toHaveBeenCalledWith(XSP_DIR_VALUE); + + // Assert: mkdirSync called with recursive true + expect(mkdirSync).toHaveBeenCalledWith('dist', { recursive: true }); + + // Assert: writeFileSync to correct path with pretty-printed JSON + expect(writeFileSync).toHaveBeenCalledTimes(1); + const [pathArg, dataArg] = writeFileSync.mock.calls[0]; + expect(pathArg).toBe('dist/schema.transitional.json'); + expect(dataArg).toBe(JSON.stringify(out, null, 2)); // pretty JSON + + // Assert: mkdirSync happened before writeFileSync + const mkdirIndex = vi.mocked(mkdirSync).mock.invocationCallOrder[0]; + const writeIndex = vi.mocked(writeFileSync).mock.invocationCallOrder[0]; + expect(mkdirIndex).toBeLessThan(writeIndex); + + // Assert: logs include header + each sample entry line + const logs = console.log.mock.calls.map((args) => args.join(' ')); + expect(logs).toContain('Wrote dist/schema.transitional.json'); + expect(logs).toContain('\nSample entries:'); + + // each key should print ": children" + expect(logs).toContain('w:document: 0 children'); + expect(logs).toContain('w:body: 1 children'); + expect(logs).toContain('w:p: 1 children'); + expect(logs).toContain('w:r: 1 children'); + expect(logs).toContain('w:t: 0 children'); + expect(logs).toContain('w:pPr: 1 children'); + expect(logs).toContain('w:rPr: 0 children'); + }); + + it('prints "not found" for missing elements', () => { + // Arrange a schema with some missing keys + const out = { + elements: { + 'w:document': { children: [], attributes: {} }, + // 'w:body' missing + 'w:p': { children: [], attributes: {} }, + 'w:r': { children: [], attributes: {} }, + // 'w:t' missing + 'w:pPr': { children: [], attributes: {} }, + // 'w:rPr' missing + }, + }; + buildFromXsdDirMock.mockReturnValue(out); + + runGenerator(); + + const logs = console.log.mock.calls.map((args) => args.join(' ')); + // present keys show count + expect(logs).toContain('w:document: 0 children'); + expect(logs).toContain('w:p: 0 children'); + expect(logs).toContain('w:r: 0 children'); + expect(logs).toContain('w:pPr: 0 children'); + + // missing keys show "not found" + expect(logs).toContain('w:body: not found children'); + expect(logs).toContain('w:t: not found children'); + expect(logs).toContain('w:rPr: not found children'); + }); +}); diff --git a/packages/ooxml-inspector/generator/src/index.js b/packages/ooxml-inspector/generator/src/index.js new file mode 100644 index 0000000000..f8088381fa --- /dev/null +++ b/packages/ooxml-inspector/generator/src/index.js @@ -0,0 +1,3 @@ +export * from './constants.js'; +export * from './generator.js'; +export * from './schema-build.js'; diff --git a/packages/ooxml-inspector/generator/src/schema-build.js b/packages/ooxml-inspector/generator/src/schema-build.js new file mode 100644 index 0000000000..a9b70d44e8 --- /dev/null +++ b/packages/ooxml-inspector/generator/src/schema-build.js @@ -0,0 +1,373 @@ +import { readdirSync, readFileSync } from 'node:fs'; +import { join } from 'node:path'; +import { NS_MAP, PASS_THROUGH } from './constants.js'; +import { arr, qn, parser, inlineCT, contentRoot } from './builder/index.js'; +import { expandContent, resolveType, collectElements, autoPrefix, resolveChildQName } from './builder/index.js'; + +/** + * Build a schema from a directory of XSD files. + * @param {string} xsdDir - Directory containing .xsd files + * @returns {import('./types/index.js').BuiltSchema} - Array of parsed XML schemas + */ +export function buildFromXsdDir(xsdDir) { + const schemas = []; + for (const f of readdirSync(xsdDir)) + if (f.endsWith('.xsd')) { + const xml = readFileSync(join(xsdDir, f), 'utf8'); + const doc = parser.parse(xml); + const schema = doc['xs:schema'] || doc['xsd:schema'] || doc['schema']; + if (schema) { + schema._filename = f; // for debugging + schemas.push(schema); + } + } + + console.log(`Loaded ${schemas.length} XSD files`); + + /** @type {Record} */ + const nsMap = NS_MAP; + + // First, collect all namespace mappings from import statements + for (const s of schemas) { + // Check for xs:import or xsd:import elements which define namespace mappings + const imports = arr(s['xs:import']).concat(arr(s['xsd:import'])); + for (const imp of imports) { + if (imp.namespace && !nsMap[imp.namespace]) { + // Auto-assign prefix if we don't have one + const prefix = 'g' + Object.keys(nsMap).length; + nsMap[imp.namespace] = prefix; + } + } + } + + const complexTypes = new Map(); // `${tns}::${name}` -> complexType + const simpleTypes = new Map(); // `${tns}::${name}` -> simpleType (for tracking) + const groups = new Map(); // `${tns}::${name}` -> group + const attributeGroups = new Map(); // `${tns}::${name}` -> attributeGroup + const elements = new Map(); // `${tns}::${name}` -> { tns,prefix,name,el } + const elementRefs = new Map(); // Track element references to resolve later + + // First pass: collect all types, groups, and top-level elements + for (const s of schemas) { + const tns = s.targetNamespace; + const prefix = autoPrefix(tns, nsMap); + + // Collect complex types and their nested elements + for (const ct of arr(s['xs:complexType']).concat(arr(s['xsd:complexType']))) { + if (ct.name) { + complexTypes.set(`${tns}::${ct.name}`, ct); + // Also collect any elements defined within this complex type + collectElements(ct, tns, prefix, elements, elementRefs); + } + } + + // Collect simple types (for tracking, not for resolution) + for (const st of arr(s['xs:simpleType']).concat(arr(s['xsd:simpleType']))) { + if (st.name) { + simpleTypes.set(`${tns}::${st.name}`, st); + } + } + + // Collect groups and their nested elements + for (const g of arr(s['xs:group']).concat(arr(s['xsd:group']))) { + if (g.name) { + groups.set(`${tns}::${g.name}`, g); + // Also collect any elements defined within this group + collectElements(g, tns, prefix, elements, elementRefs); + } + } + + // Collect attribute groups + for (const ag of arr(s['xs:attributeGroup']).concat(arr(s['xsd:attributeGroup']))) { + if (ag.name) { + attributeGroups.set(`${tns}::${ag.name}`, ag); + } + } + + // Collect top-level elements + for (const el of arr(s['xs:element']).concat(arr(s['xsd:element']))) { + if (el.name) { + const key = `${tns}::${el.name}`; + if (!elements.has(key)) { + elements.set(key, { tns, prefix, name: el.name, el }); + } + } + } + } + + // Resolve element references + for (const [ref, { tns }] of elementRefs) { + let targetTns, localName; + if (ref.includes(':')) { + const [refPrefix, local] = ref.split(':'); + localName = local; + targetTns = Object.entries(nsMap).find(([, v]) => v === refPrefix)?.[0]; + } else { + localName = ref; + targetTns = tns; + } + + if (targetTns && localName) { + const key = `${targetTns}::${localName}`; + if (!elements.has(key)) { + const targetPrefix = nsMap[targetTns] || autoPrefix(targetTns, nsMap); + // Create a synthetic element entry for the reference + elements.set(key, { + tns: targetTns, + prefix: targetPrefix, + name: localName, + el: { name: localName, type: `${targetPrefix}:${localName}Type` }, + }); + } + } + } + + // Second pass: Check for complex types that imply elements (CT_ElementName pattern) + for (const [key] of complexTypes) { + const [tns, typeName] = key.split('::'); + + // Common OOXML pattern: CT_P type implies a 'p' element + if (typeName.startsWith('CT_')) { + const elementName = typeName.substring(3); + const elementKey = `${tns}::${elementName}`; + + if (!elements.has(elementKey)) { + const prefix = nsMap[tns] || autoPrefix(tns, nsMap); + // Check if this looks like a real element name (starts with uppercase or is short) + if (elementName.length <= 10 && /^[A-Z]/.test(elementName)) { + const lowerName = elementName.charAt(0).toLowerCase() + elementName.slice(1); + const lowerKey = `${tns}::${lowerName}`; + + if (!elements.has(lowerKey)) { + // Create synthetic element for this complex type + elements.set(lowerKey, { + tns, + prefix, + name: lowerName, + el: { name: lowerName, type: typeName }, + }); + } + } + } + } + } + + console.log( + `Found ${complexTypes.size} complex types, ${simpleTypes.size} simple types, ${groups.size} groups, ${attributeGroups.size} attribute groups, ${elements.size} elements`, + ); + + // Debug: show some key elements we expect to find + const expectedElements = ['w:document', 'w:body', 'w:p', 'w:r', 'w:t', 'w:tbl']; + const foundExpected = expectedElements.filter((qname) => { + const [prefix, local] = qname.split(':'); + const tns = Object.entries(nsMap).find(([, v]) => v === prefix)?.[0]; + return tns && elements.has(`${tns}::${local}`); + }); + if (foundExpected.length > 0) { + console.log(`Found expected elements: ${foundExpected.join(', ')}`); + } + + // Helper function to extract attributes from a node + function extractDirectAttributes(node, attributes, tns) { + // Direct attributes + for (const attr of arr(node['xs:attribute']).concat(arr(node['xsd:attribute']))) { + const name = attr.name; + const ref = attr.ref; + + if (name) { + const attrName = name.includes(':') ? name : `${nsMap[tns]}:${name}`; + attributes[attrName] = { + type: attr.type || 'xs:string', + use: attr.use || 'optional', + default: attr.default, + fixed: attr.fixed, + }; + } else if (ref) { + // Resolve attribute reference + const [refPrefix, refLocal] = ref.includes(':') ? ref.split(':') : [nsMap[tns], ref]; + const attrName = `${refPrefix}:${refLocal}`; + attributes[attrName] = { + type: 'referenced', + ref: ref, + use: attr.use || 'optional', + }; + } + } + + // Attribute groups + for (const attrGroup of arr(node['xs:attributeGroup']).concat(arr(node['xsd:attributeGroup']))) { + if (attrGroup.ref) { + // Resolve attribute group + let groupTns, groupName; + if (attrGroup.ref.includes(':')) { + const [prefix, local] = attrGroup.ref.split(':'); + groupName = local; + groupTns = Object.entries(nsMap).find(([, v]) => v === prefix)?.[0]; + } else { + groupName = attrGroup.ref; + groupTns = tns; + } + + if (groupTns) { + const group = attributeGroups.get(`${groupTns}::${groupName}`); + if (group) { + // Recursively extract attributes from the group + extractDirectAttributes(group, attributes, groupTns); + } + } + } + } + + // anyAttribute allows any attributes + if (node['xs:anyAttribute'] || node['xsd:anyAttribute']) { + attributes['@anyAttribute'] = true; + } + } + + // Helper function to extract all attributes including inherited + function extractAttributesComplete(ct, tns) { + const attributes = {}; + + if (!ct) return attributes; + + // Handle inheritance first + const complexContent = ct['xs:complexContent'] || ct['xsd:complexContent']; + if (complexContent) { + const extension = complexContent['xs:extension'] || complexContent['xsd:extension']; + const restriction = complexContent['xs:restriction'] || complexContent['xsd:restriction']; + + const base = extension?.base || restriction?.base; + if (base) { + // Resolve base type and get its attributes + const baseType = resolveType(base, tns, nsMap, complexTypes, simpleTypes); + if (baseType) { + const baseAttrs = extractAttributesComplete(baseType, tns); + Object.assign(attributes, baseAttrs); + } + } + + // Process extension/restriction's own attributes + const content = extension || restriction; + if (content) { + extractDirectAttributes(content, attributes, tns); + } + } + + // Simple content (often has attributes) + const simpleContent = ct['xs:simpleContent'] || ct['xsd:simpleContent']; + if (simpleContent) { + const extension = simpleContent['xs:extension'] || simpleContent['xsd:extension']; + const restriction = simpleContent['xs:restriction'] || simpleContent['xsd:restriction']; + const content = extension || restriction; + if (content) { + extractDirectAttributes(content, attributes, tns); + } + } + + // Direct attributes on the complex type + extractDirectAttributes(ct, attributes, tns); + + return attributes; + } + + /** @type {Record}>} */ + const map = {}; // QName -> {children: [], attributes: {}} + let processedCount = 0; + let debugElements = ['w:p', 'w:r', 'w:pPr', 'w:rPr', 'w:tbl', 'w:document', 'w:body']; + + // Also check for elements that appear as references but aren't defined + const referencedElements = new Set(); + + for (const { tns, prefix, name, el } of elements.values()) { + const qname = qn(prefix, name); + const ct = inlineCT(el) || resolveType(el.type, tns, nsMap, complexTypes, simpleTypes); + const childrenSet = new Set(); + let attributes = {}; + + if (debugElements.includes(qname)) { + console.log(`\n=== Processing ${qname} ===`); + console.log(`Element type: ${el.type || 'inline'}`); + console.log(`Has inline complexType: ${!!inlineCT(el)}`); + console.log(`Resolved complexType: ${!!ct}`); + } + + if (ct) { + // Extract attributes + attributes = extractAttributesComplete(ct, tns); + + const root = contentRoot(ct); + if (debugElements.includes(qname)) { + console.log(`Content root: ${!!root}`); + console.log(`Attributes found: ${Object.keys(attributes).length}`); + } + + if (root) { + const parts = []; + expandContent(root, parts, tns, 0, elements, nsMap, groups); + + if (debugElements.includes(qname)) { + console.log(`Found ${parts.length} child elements in content model`); + } + + for (const e of parts) { + const childQName = resolveChildQName(e, tns, nsMap); + if (childQName) { + childrenSet.add(childQName); + referencedElements.add(childQName); // Track that this element is referenced + if (debugElements.includes(qname)) { + console.log(` Child: ${childQName} (from ${e.name || e.ref})`); + } + } + } + } + } else if (debugElements.includes(qname)) { + console.log(`No complex type found for ${qname}`); + } + + // Add pass-through elements for content containers + if (childrenSet.size > 0 || ['w:p', 'w:tc', 'w:body', 'w:document'].includes(qname)) { + for (const pt of PASS_THROUGH) { + childrenSet.add(pt); + } + } + + // Store both children and attributes + map[qname] = { + children: Array.from(childrenSet).sort(), + attributes: attributes, + }; + + if (map[qname].children.length > 0) { + processedCount++; + } + + // Show final result for debug elements + if (debugElements.includes(qname)) { + console.log(`Final children for ${qname}: [${map[qname].children.join(', ')}]`); + if (Object.keys(attributes).length > 0) { + console.log(`Attributes for ${qname}: ${Object.keys(attributes).join(', ')}`); + } + } + } + + // Add entries for referenced elements that weren't defined + for (const refQName of referencedElements) { + if (!map[refQName]) { + // This element was referenced but not defined - add empty entry + map[refQName] = { + children: [], + attributes: {}, + }; + + // Also add pass-through elements for known containers + if (['w:p', 'w:tc', 'w:body'].includes(refQName)) { + map[refQName].children = Array.from(PASS_THROUGH).sort(); + } + } + } + + console.log(`Generated schema with ${processedCount} elements having children`); + console.log(`Total elements in schema: ${Object.keys(map).length}`); + + return { namespaces: nsMap, elements: map }; +} diff --git a/packages/ooxml-inspector/generator/src/schema-build.test.js b/packages/ooxml-inspector/generator/src/schema-build.test.js new file mode 100644 index 0000000000..daa6fa4e0e --- /dev/null +++ b/packages/ooxml-inspector/generator/src/schema-build.test.js @@ -0,0 +1,584 @@ +// schema-build.test.js +import { describe, it, expect, beforeEach, vi } from 'vitest'; + +const H = vi.hoisted(() => ({ + PASS_THROUGH: ['w:bookmarkStart', 'w:bookmarkEnd'], + parserParse: vi.fn(), +})); + +// --- core mocks (must be defined before importing SUT) --- +vi.mock('node:fs', () => ({ + readdirSync: vi.fn(), + readFileSync: vi.fn(), +})); +vi.mock('node:path', () => ({ + join: vi.fn((...p) => p.join('/')), +})); +vi.mock('./constants.js', () => { + const NS_MAP = { 'urn:w': 'w' }; // fresh object per module load; we reset per test + return { NS_MAP, PASS_THROUGH: H.PASS_THROUGH }; +}); +vi.mock('./builder/index.js', () => { + const arr = (x) => (Array.isArray(x) ? x : x ? [x] : []); + return { + arr: vi.fn(arr), + qn: vi.fn((p, l) => `${p}:${l}`), + parser: { parse: H.parserParse }, // hoist-safe + inlineCT: vi.fn(() => null), + contentRoot: vi.fn(() => null), + expandContent: vi.fn(), + resolveType: vi.fn(() => null), + collectElements: vi.fn(), + autoPrefix: vi.fn((tns, nsMap) => { + if (!nsMap[tns]) nsMap[tns] = `g${Object.keys(nsMap).length}`; + return nsMap[tns]; + }), + resolveChildQName: vi.fn(), + }; +}); + +// Import SUT after mocks +import { readdirSync, readFileSync } from 'node:fs'; +import { buildFromXsdDir } from './schema-build.js'; + +// Helpers to access mocked modules +const getConstants = async () => await import('./constants.js'); +const getBuilder = async () => await import('./builder/index.js'); + +beforeEach(async () => { + vi.clearAllMocks(); + H.parserParse.mockReset(); + + // Reset mutable NS_MAP for isolation + const { NS_MAP } = await getConstants(); + for (const k of Object.keys(NS_MAP)) delete NS_MAP[k]; + Object.assign(NS_MAP, { 'urn:w': 'w' }); + + // Reset builder mocks (keep their identity) + const b = await getBuilder(); + b.arr.mockClear(); + b.qn.mockClear(); + b.inlineCT.mockReset().mockImplementation(() => null); + b.contentRoot.mockReset().mockImplementation(() => null); + b.expandContent.mockReset(); + b.resolveType.mockReset().mockImplementation(() => null); + b.collectElements.mockReset(); + b.autoPrefix.mockClear(); // default impl ok + b.resolveChildQName.mockReset(); +}); + +describe('schema-build', () => { + it('reads only .xsd files', async () => { + readdirSync.mockReturnValueOnce(['a.xsd', 'b.txt', 'c.xsd']); + H.parserParse + .mockReturnValueOnce({ 'xs:schema': { targetNamespace: 'urn:w' } }) + .mockReturnValueOnce({ 'xs:schema': { targetNamespace: 'urn:w' } }); + + const res = buildFromXsdDir('/fake'); + expect(H.parserParse).toHaveBeenCalledTimes(2); + expect(res.namespaces['urn:w']).toBe('w'); + expect(typeof res.elements).toBe('object'); + }); + + it('adds namespace mappings from xs:import and auto-assigns prefixes', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:import': [{ namespace: 'urn:a' }, { namespace: 'urn:b' }, { namespace: 'urn:a' }], + }, + }); + + const res = buildFromXsdDir('/fake'); + expect(res.namespaces['urn:w']).toBe('w'); + expect(res.namespaces['urn:a']).toBeDefined(); + expect(res.namespaces['urn:b']).toBeDefined(); + expect(res.namespaces['urn:a']).not.toBe('w'); + expect(res.namespaces['urn:b']).not.toBe('w'); + }); + + it('collects top-level elements and resolves children via contentRoot/expandContent/resolveChildQName', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'document', type: 'w:DocumentType' }], + 'xs:complexType': [{ name: 'DocumentType' }], + }, + }); + + const b = await getBuilder(); + b.resolveType.mockImplementation((t) => (t === 'w:DocumentType' ? { name: 'DocumentType' } : null)); + b.contentRoot.mockReturnValueOnce({ tag: 'root' }); + b.expandContent.mockImplementation((_root, parts) => { + parts.push({ name: 'body' }, { ref: 'w:p' }); + }); + b.resolveChildQName.mockImplementation((e, tns, nsMap) => (e.name ? `${nsMap[tns]}:${e.name}` : e.ref)); + + const res = buildFromXsdDir('/fake'); + expect(res.elements['w:document']).toBeDefined(); + const kids = res.elements['w:document'].children; + expect(kids).toEqual(expect.arrayContaining(['w:body', 'w:p', ...H.PASS_THROUGH])); + }); + + it('resolves elementRefs into synthetic elements when not already defined', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'wrapper', type: 'w:WrapperType' }], + 'xs:complexType': [{ name: 'WrapperType' }], + }, + }); + + const b = await getBuilder(); + b.resolveType.mockReturnValueOnce({ name: 'WrapperType' }); + b.contentRoot.mockReturnValueOnce({}); + // When collectElements is called, stash an unresolved ref + b.collectElements.mockImplementation((_node, _tns, _pfx, _elements, elementRefs) => { + elementRefs.set('w:tbl', { tns: 'urn:w', prefix: 'w' }); + }); + // And reference it in children too, to mark it as "referenced" + b.expandContent.mockImplementation((_root, parts) => parts.push({ ref: 'w:tbl' })); + b.resolveChildQName.mockImplementation((e) => e.ref); + + const res = buildFromXsdDir('/fake'); + expect(res.elements['w:tbl']).toBeDefined(); + expect(res.elements['w:tbl'].children).toEqual([]); + expect(res.elements['w:tbl'].attributes).toEqual({}); + }); + + it('creates synthetic elements from CT_ pattern (CT_P -> w:p) when missing', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:complexType': [{ name: 'CT_P' }], + }, + }); + + const res = buildFromXsdDir('/fake'); + expect(res.elements['w:p']).toBeDefined(); + // containers get pass-through + expect(res.elements['w:p'].children).toEqual([...H.PASS_THROUGH].sort()); + }); + + it('extracts direct and simpleContent attributes', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'r', type: 'w:RunType' }], + 'xs:complexType': [{ name: 'RunType' }], + }, + }); + + const b = await getBuilder(); + b.resolveType.mockImplementation((t) => + t === 'w:RunType' + ? { + 'xs:simpleContent': { + 'xs:extension': { + 'xs:attribute': [{ name: 'val', type: 'xs:string', use: 'optional' }], + }, + }, + 'xs:attribute': [{ name: 'color', type: 'xs:string' }], + } + : null, + ); + b.contentRoot.mockReturnValue(null); + + const res = buildFromXsdDir('/fake'); + const attrs = res.elements['w:r'].attributes; + expect(attrs['w:val']).toMatchObject({ type: 'xs:string', use: 'optional' }); + expect(attrs['w:color']).toMatchObject({ type: 'xs:string' }); + }); + + it('resolves attributeGroup refs and anyAttribute', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'el', type: 'w:ElType' }], + 'xs:complexType': [ + { + name: 'ElType', + 'xs:complexContent': { + 'xs:extension': { + base: 'w:Base', + 'xs:attributeGroup': [{ ref: 'w:runAttrs' }], + 'xs:anyAttribute': {}, + }, + }, + }, + { + name: 'Base', + 'xs:attribute': [{ name: 'baseAttr', type: 'xs:string' }], + }, + ], + 'xs:attributeGroup': [ + { + name: 'runAttrs', + 'xs:attribute': [{ name: 'id', type: 'xs:string' }], + }, + ], + }, + }); + + const b = await getBuilder(); + // Resolve base to the second CT so inheritance pulls baseAttr + b.resolveType.mockImplementation((t) => + t === 'w:ElType' + ? { + 'xs:complexContent': { + 'xs:extension': { base: 'w:Base', 'xs:attributeGroup': [{ ref: 'w:runAttrs' }], 'xs:anyAttribute': {} }, + }, + } + : t === 'w:Base' + ? { 'xs:attribute': [{ name: 'baseAttr', type: 'xs:string' }] } + : null, + ); + b.contentRoot.mockReturnValue(null); + + const res = buildFromXsdDir('/fake'); + const attrs = res.elements['w:el'].attributes; + expect(attrs['w:baseAttr']).toMatchObject({ type: 'xs:string' }); + expect(attrs['w:id']).toMatchObject({ type: 'xs:string' }); + expect(attrs['@anyAttribute']).toBe(true); + }); + + it('adds pass-through when element has children OR is a known container', async () => { + // Case 1: known container with no type -> still gets pass-through + readdirSync.mockReturnValueOnce(['c1.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'document' }], // no type, no ct + }, + }); + + let res = buildFromXsdDir('/fake1'); + expect(res.elements['w:document'].children).toEqual(expect.arrayContaining(H.PASS_THROUGH)); + + // Case 2: non-container but has children -> gets pass-through too + // Reset parser for new run + readdirSync.mockReturnValueOnce(['c2.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'z', type: 'w:ZType' }], + 'xs:complexType': [{ name: 'ZType' }], + }, + }); + const b = await getBuilder(); + b.resolveType.mockReturnValueOnce({ name: 'ZType' }); + b.contentRoot.mockReturnValueOnce({}); + b.expandContent.mockImplementation((_root, parts) => parts.push({ name: 'zz' })); + b.resolveChildQName.mockImplementation((e, tns, nsMap) => `${nsMap[tns]}:${e.name}`); + + res = buildFromXsdDir('/fake2'); + expect(res.elements['w:z'].children).toEqual(expect.arrayContaining(['w:zz', ...H.PASS_THROUGH])); + }); + + it('adds stub entries for referenced-but-undefined elements (non-container)', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'wrapper', type: 'w:WrapperType' }], + 'xs:complexType': [{ name: 'WrapperType' }], + }, + }); + + const b = await getBuilder(); + b.resolveType.mockReturnValueOnce({ name: 'WrapperType' }); + b.contentRoot.mockReturnValueOnce({}); + b.expandContent.mockImplementation((_root, parts) => parts.push({ ref: 'w:foo' })); + b.resolveChildQName.mockImplementation((e) => e.ref); + + const res = buildFromXsdDir('/fake'); + expect(res.elements['w:foo']).toEqual({ children: [], attributes: {} }); + }); + + it('supports xsd:schema and xsd:import variants', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + // Use xsd:schema (not xs:schema) and xsd:import (not xs:import) + H.parserParse.mockReturnValueOnce({ + 'xsd:schema': { + targetNamespace: 'urn:w', + 'xsd:import': [{ namespace: 'urn:a' }], + }, + }); + + const res = buildFromXsdDir('/fake'); + // namespace map should include original and imported one (auto-assigned) + expect(res.namespaces['urn:w']).toBe('w'); + expect(res.namespaces['urn:a']).toBeDefined(); + expect(res.namespaces['urn:a']).not.toBe('w'); + }); + + it('resolves elementRefs with unprefixed refs (falls back to same TNS)', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'wrapper', type: 'w:WrapperType' }], + 'xs:complexType': [{ name: 'WrapperType' }], + }, + }); + + const b = await getBuilder(); + b.resolveType.mockReturnValueOnce({ name: 'WrapperType' }); + b.contentRoot.mockReturnValueOnce({}); + // collectElements adds an unresolved **unprefixed** ref: "tbl" + b.collectElements.mockImplementation((_node, tns, prefix, _elements, elementRefs) => { + elementRefs.set('tbl', { tns: 'urn:w', prefix: 'w' }); + }); + // also reference it in content to mark it "referenced" + b.expandContent.mockImplementation((_root, parts) => parts.push({ ref: 'tbl' })); + b.resolveChildQName.mockImplementation((e) => (e.ref.includes(':') ? e.ref : `w:${e.ref}`)); + + const res = buildFromXsdDir('/fake'); + expect(res.elements['w:tbl']).toBeDefined(); + // created as synthetic (empty children/attrs) + expect(res.elements['w:tbl'].children).toEqual([]); + expect(res.elements['w:tbl'].attributes).toEqual({}); + }); + + it('does NOT create CT_ synthetic element when heuristic fails (name too long)', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + // CT_ name > 10 chars after "CT_" so heuristic should skip creating element + 'xs:complexType': [{ name: 'CT_ThisNameIsDefinitelyLong' }], + }, + }); + + const res = buildFromXsdDir('/fake'); + // Should NOT synthesize w:thisNameIsDefinitelyLong + const maybe = Object.keys(res.elements).find((q) => /thisNameIsDefinitelyLong/i.test(q)); + expect(maybe).toBeUndefined(); + }); + + it('extractDirectAttributes: resolves unprefixed attribute ref using current TNS', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'el', type: 'w:ElType' }], + 'xs:complexType': [ + { + name: 'ElType', + 'xs:complexContent': { + 'xs:extension': { + base: 'w:Base', + // attribute ref WITHOUT prefix; should attach as "w:id" + 'xs:attribute': [{ ref: 'id', use: 'optional' }], + }, + }, + }, + { + name: 'Base', + 'xs:attribute': [{ name: 'baseAttr', type: 'xs:string' }], + }, + ], + }, + }); + + const b = await getBuilder(); + b.resolveType + .mockImplementationOnce((_t) => ({ + // resolve ElType + 'xs:complexContent': { + 'xs:extension': { base: 'w:Base', 'xs:attribute': [{ ref: 'id', use: 'optional' }] }, + }, + })) + .mockImplementationOnce((_t) => ({ + // resolve Base + 'xs:attribute': [{ name: 'baseAttr', type: 'xs:string' }], + })); + b.contentRoot.mockReturnValue(null); + + const res = buildFromXsdDir('/fake'); + const attrs = res.elements['w:el'].attributes; + expect(attrs['w:baseAttr']).toMatchObject({ type: 'xs:string' }); + // unprefixed ref -> prefix from current TNS (w) + expect(attrs['w:id']).toMatchObject({ type: 'referenced', ref: 'id', use: 'optional' }); + }); + + it('attributeGroup ref without prefix resolves within same TNS', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'el', type: 'w:ElType' }], + 'xs:complexType': [ + { + name: 'ElType', + 'xs:complexContent': { + 'xs:extension': { + base: 'w:Base', + // attributeGroup ref WITHOUT prefix; should pull group from same TNS + 'xs:attributeGroup': [{ ref: 'runAttrs' }], + 'xs:anyAttribute': {}, // we’ll also hit the xsd:anyAttribute in the next test + }, + }, + }, + { name: 'Base', 'xs:attribute': [{ name: 'fromBase', type: 'xs:string' }] }, + ], + 'xs:attributeGroup': [{ name: 'runAttrs', 'xs:attribute': [{ name: 'id', type: 'xs:string' }] }], + }, + }); + + const b = await getBuilder(); + b.resolveType + .mockImplementationOnce((_t) => ({ + // ElType + 'xs:complexContent': { + 'xs:extension': { + base: 'w:Base', + 'xs:attributeGroup': [{ ref: 'runAttrs' }], + 'xs:anyAttribute': {}, + }, + }, + })) + .mockImplementationOnce((_t) => ({ + // Base + 'xs:attribute': [{ name: 'fromBase', type: 'xs:string' }], + })); + b.contentRoot.mockReturnValue(null); + + const res = buildFromXsdDir('/fake'); + const attrs = res.elements['w:el'].attributes; + expect(attrs['w:fromBase']).toMatchObject({ type: 'xs:string' }); + // group from same TNS (ref had no prefix) + expect(attrs['w:id']).toMatchObject({ type: 'xs:string' }); + expect(attrs['@anyAttribute']).toBe(true); + }); + + it('recognizes xsd:anyAttribute as well as xs:anyAttribute', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:element': [{ name: 'el', type: 'w:ElType' }], + 'xs:complexType': [ + { + name: 'ElType', + 'xs:simpleContent': { + 'xs:extension': { + // specifically test the xsd:anyAttribute branch here + 'xsd:anyAttribute': {}, + }, + }, + }, + ], + }, + }); + + const b = await getBuilder(); + b.resolveType.mockImplementation((_t) => ({ + 'xs:simpleContent': { 'xs:extension': { 'xsd:anyAttribute': {} } }, + })); + b.contentRoot.mockReturnValue(null); + + const res = buildFromXsdDir('/fake'); + const attrs = res.elements['w:el'].attributes; + expect(attrs['@anyAttribute']).toBe(true); + }); + + it('ignores xs:import entries without a namespace', async () => { + readdirSync.mockReturnValueOnce(['doc.xsd']); + // imports include missing/empty namespace → should be ignored + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:import': [{}, { namespace: '' }], + }, + }); + + const res = buildFromXsdDir('/fake'); + // Should only have the original mapping; no new prefixes created + expect(res.namespaces['urn:w']).toBe('w'); + // no bogus keys like '' or undefined + expect(Object.keys(res.namespaces)).toEqual(expect.arrayContaining(['urn:w'])); + expect(Object.keys(res.namespaces)).not.toContain(''); + }); + + it('does not overwrite an existing namespace mapping from xs:import', async () => { + // Pre-seed NS_MAP with an existing mapping + const { NS_MAP } = await getConstants(); + NS_MAP['urn:a'] = 'a'; + + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + // one already-mapped (urn:a), one new (urn:b) + 'xs:import': [{ namespace: 'urn:a' }, { namespace: 'urn:b' }], + }, + }); + + const res = buildFromXsdDir('/fake'); + + // Existing mapping preserved + expect(res.namespaces['urn:a']).toBe('a'); + + // New mapping auto-assigned (not 'w' or 'a') + expect(res.namespaces['urn:b']).toBeDefined(); + expect(['w', 'a']).not.toContain(res.namespaces['urn:b']); + }); + + it('normalizes single-object xs:import and xsd:import via arr(...) and assigns prefixes for both', async () => { + // Two files so each schema variant is processed (the SUT picks one schema per file) + readdirSync.mockReturnValueOnce(['a.xsd', 'b.xsd']); + + H.parserParse + // File 1: xs:schema with single-object xs:import + .mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:import': { namespace: 'urn:a' }, // not an array + }, + }) + // File 2: xsd:schema with single-object xsd:import + .mockReturnValueOnce({ + 'xsd:schema': { + targetNamespace: 'urn:w', + 'xsd:import': { namespace: 'urn:b' }, // not an array + }, + }); + + const res = buildFromXsdDir('/fake'); + + expect(res.namespaces['urn:w']).toBe('w'); + expect(res.namespaces['urn:a']).toBeDefined(); + expect(res.namespaces['urn:b']).toBeDefined(); + expect(res.namespaces['urn:a']).not.toBe('w'); + expect(res.namespaces['urn:b']).not.toBe('w'); + expect(res.namespaces['urn:a']).not.toBe(res.namespaces['urn:b']); // distinct autoprefixes + }); + + it('re-assigns a prefix when the namespace exists with a falsy mapping (e.g., empty string)', async () => { + // Pre-seed NS_MAP with a falsy mapping for a namespace + const { NS_MAP } = await getConstants(); + NS_MAP['urn:empty'] = ''; // falsy -> condition `!nsMap[imp.namespace]` should pass + + readdirSync.mockReturnValueOnce(['doc.xsd']); + H.parserParse.mockReturnValueOnce({ + 'xs:schema': { + targetNamespace: 'urn:w', + 'xs:import': [{ namespace: 'urn:empty' }], + }, + }); + + const res = buildFromXsdDir('/fake'); + + // Should get a real auto-assigned prefix (non-empty string) + expect(res.namespaces['urn:empty']).toBeDefined(); + expect(res.namespaces['urn:empty']).not.toBe(''); + // And not collide with 'w' + expect(res.namespaces['urn:empty']).not.toBe('w'); + }); +}); diff --git a/packages/ooxml-inspector/generator/src/types/index.js b/packages/ooxml-inspector/generator/src/types/index.js new file mode 100644 index 0000000000..255a7e010e --- /dev/null +++ b/packages/ooxml-inspector/generator/src/types/index.js @@ -0,0 +1,14 @@ +/** + * @typedef {Object} SchemaElement + * @property {string[]} children - List of child element QNames + * @property {Record} attributes - Attributes keyed by QName + * @property {string} [length] - The length of the element + */ + +/** + * @typedef {Object} BuiltSchema + * @property {Record} namespaces - Mapping of namespace URI → prefix + * @property {Record} elements - Mapping of QName → schema element definition + */ + +export {}; diff --git a/packages/ooxml-inspector/package.json b/packages/ooxml-inspector/package.json new file mode 100644 index 0000000000..c2354d33c4 --- /dev/null +++ b/packages/ooxml-inspector/package.json @@ -0,0 +1,53 @@ +{ + "name": "@superdoc-dev/ooxml-inspector", + "version": "1.0.1", + "type": "module", + "license": "AGPL-3.0", + "engines": { + "node": ">=18.17" + }, + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "bin": { + "ooxml": "./dist/bin/cli.js" + }, + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./schema": "./dist/schema.transitional.json", + "./cli": "./dist/bin/cli.js", + "./package.json": "./package.json" + }, + "files": [ + "dist/", + "README.md", + "LICENSE" + ], + "scripts": { + "clean": "rm -rf dist coverage", + "build:schema": "node generator/index.js", + "build:lib": "tsup src/index.js --format esm --dts --sourcemap --out-dir dist", + "build:cli": "tsup src/cli.js --format esm --sourcemap --out-dir dist/bin", + "build": "npm run clean && npm run build:schema && npm run build:lib && npm run build:cli", + "prepublishOnly": "npm run test && npm run build", + "test": "vitest run", + "test:watch": "vitest", + "test:cov": "vitest run --coverage" + }, + "sideEffects": false, + "publishConfig": { + "access": "public" + }, + "dependencies": { + "fast-xml-parser": "^4.4.0" + }, + "devDependencies": { + "@types/node": "^24.3.0", + "@vitest/coverage-v8": "^3.2.4", + "tsup": "^8.1.0", + "typescript": "^5.9.2", + "vitest": "^3.2.4" + } +} diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chart.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chart.xsd new file mode 100644 index 0000000000..bc325f9f5e --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chart.xsd @@ -0,0 +1,1499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chartDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chartDrawing.xsd new file mode 100644 index 0000000000..afa4f463e3 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-chartDrawing.xsd @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-diagram.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-diagram.xsd new file mode 100644 index 0000000000..40e4b12a8e --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-diagram.xsd @@ -0,0 +1,1085 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-lockedCanvas.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-lockedCanvas.xsd new file mode 100644 index 0000000000..687eea8297 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-lockedCanvas.xsd @@ -0,0 +1,11 @@ + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-main.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-main.xsd new file mode 100644 index 0000000000..c8c127842a --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-main.xsd @@ -0,0 +1,3081 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-picture.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-picture.xsd new file mode 100644 index 0000000000..1dbf05140d --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-picture.xsd @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-spreadsheetDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-spreadsheetDrawing.xsd new file mode 100644 index 0000000000..f1af17db4e --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-spreadsheetDrawing.xsd @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-wordprocessingDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-wordprocessingDrawing.xsd new file mode 100644 index 0000000000..5c00a6ffc4 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/dml-wordprocessingDrawing.xsd @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/pml.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/pml.xsd new file mode 100644 index 0000000000..2b0bc506a3 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/pml.xsd @@ -0,0 +1,1676 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-additionalCharacteristics.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-additionalCharacteristics.xsd new file mode 100644 index 0000000000..c20f3bf147 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-additionalCharacteristics.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-bibliography.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-bibliography.xsd new file mode 100644 index 0000000000..ac60252262 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-bibliography.xsd @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-commonSimpleTypes.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-commonSimpleTypes.xsd new file mode 100644 index 0000000000..7fa4d9277b --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-commonSimpleTypes.xsd @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlDataProperties.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlDataProperties.xsd new file mode 100644 index 0000000000..2bddce2921 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlDataProperties.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlSchemaProperties.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlSchemaProperties.xsd new file mode 100644 index 0000000000..8a8c18ba2d --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-customXmlSchemaProperties.xsd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesCustom.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesCustom.xsd new file mode 100644 index 0000000000..5c42706a0d --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesCustom.xsd @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesExtended.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesExtended.xsd new file mode 100644 index 0000000000..853c341c87 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesExtended.xsd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesVariantTypes.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesVariantTypes.xsd new file mode 100644 index 0000000000..da835ee82d --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-documentPropertiesVariantTypes.xsd @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-math.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-math.xsd new file mode 100644 index 0000000000..a07f392784 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-math.xsd @@ -0,0 +1,582 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-relationshipReference.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-relationshipReference.xsd new file mode 100644 index 0000000000..9e86f1b2be --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/shared-relationshipReference.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/sml.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/sml.xsd new file mode 100644 index 0000000000..6f226ae413 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/sml.xsd @@ -0,0 +1,4425 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-main.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-main.xsd new file mode 100644 index 0000000000..eeb4ef8fa0 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-main.xsd @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-officeDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-officeDrawing.xsd new file mode 100644 index 0000000000..ca2575c753 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-officeDrawing.xsd @@ -0,0 +1,509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-presentationDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-presentationDrawing.xsd new file mode 100644 index 0000000000..dd079e603f --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-presentationDrawing.xsd @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-spreadsheetDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-spreadsheetDrawing.xsd new file mode 100644 index 0000000000..3dd6cf625a --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-spreadsheetDrawing.xsd @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-wordprocessingDrawing.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-wordprocessingDrawing.xsd new file mode 100644 index 0000000000..f1041e34ef --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/vml-wordprocessingDrawing.xsd @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/wml.xsd b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/wml.xsd new file mode 100644 index 0000000000..28c23061a1 --- /dev/null +++ b/packages/ooxml-inspector/specification/OfficeOpenXML-XMLSchema-Transitional/wml.xsd @@ -0,0 +1,3644 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ooxml-inspector/src/children/cli.js b/packages/ooxml-inspector/src/children/cli.js new file mode 100644 index 0000000000..f4b15d8d24 --- /dev/null +++ b/packages/ooxml-inspector/src/children/cli.js @@ -0,0 +1,82 @@ +import { childrenOf, allTags, namespaces } from './lookup.js'; +import { getAttributes } from './index.js'; + +export function runChildrenCLI(argv) { + const sub = argv[0]; + const arg = argv[1]; + + switch (sub) { + case 'children': { + if (!arg) { + console.error('Usage: ooxml children '); + process.exit(2); + } + console.log(JSON.stringify(childrenOf(arg), null, 2)); + break; + } + + case 'tags': { + const prefix = arg && !arg.startsWith('--') ? arg : null; + const flags = new Set(argv.slice(prefix ? 2 : 1).filter((a) => a.startsWith('--'))); + const parentsOnly = flags.has('--parents'); + const plain = flags.has('--plain'); + const tags = allTags({ prefix, hasChildren: parentsOnly ? true : null }); + console.log(plain ? tags.join('\n') : JSON.stringify({ count: tags.length, tags }, null, 2)); + console.log(`Total tags: ${tags.length}`); + break; + } + + case 'namespaces': { + console.log(JSON.stringify(namespaces(), null, 2)); + break; + } + + case 'attrs': { + if (!arg) return usage(); + const attrs = getAttributes(arg); + if (attrs == null) notFound(arg); + else { + const keys = Object.keys(attrs); + if (!keys.length) { + console.log('(no attributes)'); + break; + } + for (const k of keys) { + const spec = attrs[k]; + const bits = []; + if (spec.use) bits.push(`use=${spec.use}`); + if (spec.type) bits.push(`type=${spec.type}`); + if (spec.default != null) bits.push(`default=${spec.default}`); + if (spec.fixed != null) bits.push(`fixed=${spec.fixed}`); + if (spec.ref) bits.push(`ref=${spec.ref}`); + console.log(`${k}${bits.length ? ' ' + bits.join(' ') : ''}`); + } + } + break; + } + + default: + console.error( + 'Usage:\n ooxml children \n ooxml tags [prefix] [--parents] [--plain]\n ooxml namespaces', + ); + process.exit(2); + } +} + +function usage() { + console.error( + `Usage: + ooxml children # list allowed children for a tag + ooxml attrs # list allowed attributes for a tag + ooxml tags # list all known tags (QNames) + ooxml namespaces # list namespace prefix map +Options: + -j, --json # JSON output`, + ); + process.exit(2); +} + +function notFound(q) { + console.error(`Unknown element: ${q}`); + process.exit(2); +} diff --git a/packages/ooxml-inspector/src/children/cli.test.js b/packages/ooxml-inspector/src/children/cli.test.js new file mode 100644 index 0000000000..88cfe9e8a5 --- /dev/null +++ b/packages/ooxml-inspector/src/children/cli.test.js @@ -0,0 +1,169 @@ +import { describe, it, beforeEach, afterEach, expect, vi } from 'vitest'; + +vi.mock('./lookup.js', () => ({ + childrenOf: vi.fn(), + allTags: vi.fn(), + namespaces: vi.fn(), +})); +vi.mock('./index.js', () => ({ + getAttributes: vi.fn(), +})); + +import { childrenOf, allTags, namespaces } from './lookup.js'; +import { getAttributes } from './index.js'; +import { runChildrenCLI } from './cli.js'; + +// Helper to make process.exit stop execution but assert exit code +class ExitError extends Error { + constructor(code) { + super(`__EXIT__:${code}`); + this.code = code; + } +} + +describe('runChildrenCLI', () => { + let logSpy, errSpy, exitSpy; + + beforeEach(() => { + vi.clearAllMocks(); + logSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); + errSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + exitSpy = vi.spyOn(process, 'exit').mockImplementation((code) => { + throw new ExitError(code); + }); + }); + + afterEach(() => { + logSpy.mockRestore(); + errSpy.mockRestore(); + exitSpy.mockRestore(); + }); + + it('children: exits with usage when missing qname', () => { + expect(() => runChildrenCLI(['children'])).toThrow(ExitError); + expect(errSpy).toHaveBeenCalledWith('Usage: ooxml children '); + // exit code 2 + try { + runChildrenCLI(['children']); + } catch (e) { + expect(e).toBeInstanceOf(ExitError); + expect(e.code).toBe(2); + } + expect(childrenOf).not.toHaveBeenCalled(); + }); + + it('children: prints JSON children array for provided qname', () => { + childrenOf.mockReturnValue(['w:r', 'w:p']); + runChildrenCLI(['children', 'w:body']); + expect(childrenOf).toHaveBeenCalledWith('w:body'); + // first arg to a JSON.stringify log is the stringified array (pretty-printed) + const out = logSpy.mock.calls.map((c) => c[0]).join('\n'); + expect(out).toContain('"w:r"'); + expect(out).toContain('"w:p"'); + expect(errSpy).not.toHaveBeenCalled(); + }); + + it('tags: no args → JSON with count & tags, then "Total tags:" line', () => { + allTags.mockReturnValue(['w:p', 'w:r', 'a:blip']); + runChildrenCLI(['tags']); + expect(allTags).toHaveBeenCalledWith({ prefix: null, hasChildren: null }); + const calls = logSpy.mock.calls.map((c) => c[0]); + expect(calls[0]).toMatch(/"count":\s*3/); + expect(calls[0]).toMatch(/"tags":\s*\[/); + expect(calls[1]).toBe('Total tags: 3'); + }); + + it('tags: with prefix and --parents → filters via hasChildren=true', () => { + allTags.mockReturnValue(['w:p', 'w:r']); + runChildrenCLI(['tags', 'w', '--parents']); + expect(allTags).toHaveBeenCalledWith({ prefix: 'w', hasChildren: true }); + const calls = logSpy.mock.calls.map((c) => c[0]); + expect(calls[0]).toMatch(/"count":\s*2/); + expect(calls[1]).toBe('Total tags: 2'); + }); + + it('tags: --plain outputs newline-joined list + Total tags', () => { + allTags.mockReturnValue(['w:p', 'w:r', 'w:tbl']); + runChildrenCLI(['tags', '--plain']); + // plain should not JSON.stringify the payload; just join with \n + const calls = logSpy.mock.calls.map((c) => c[0]); + expect(calls[0]).toBe('w:p\nw:r\nw:tbl'); + expect(calls[1]).toBe('Total tags: 3'); + }); + + it('tags: prefix + --plain + --parents parses flags after prefix', () => { + allTags.mockReturnValue(['w:p']); + runChildrenCLI(['tags', 'w', '--plain', '--parents']); + expect(allTags).toHaveBeenCalledWith({ prefix: 'w', hasChildren: true }); + const calls = logSpy.mock.calls.map((c) => c[0]); + expect(calls[0]).toBe('w:p'); + expect(calls[1]).toBe('Total tags: 1'); + }); + + it('namespaces: prints JSON of namespaces()', () => { + namespaces.mockReturnValue({ w: 'http://schemas.openxmlformats.org/wordprocessingml/2006/main' }); + runChildrenCLI(['namespaces']); + const first = logSpy.mock.calls[0][0]; + expect(first).toContain('"w"'); + expect(first).toContain('wordprocessingml'); + }); + + it('attrs: no qname → usage() and exit 2', () => { + expect(() => runChildrenCLI(['attrs'])).toThrow(ExitError); + expect(errSpy.mock.calls.map((c) => c[0]).join('\n')).toMatch(/Usage:/); + try { + runChildrenCLI(['attrs']); + } catch (e) { + expect(e).toBeInstanceOf(ExitError); + expect(e.code).toBe(2); + } + expect(getAttributes).not.toHaveBeenCalled(); + }); + + it('attrs: unknown element (null) → notFound and exit 2', () => { + getAttributes.mockReturnValue(null); + expect(() => runChildrenCLI(['attrs', 'w:oops'])).toThrow(ExitError); + expect(errSpy).toHaveBeenCalledWith('Unknown element: w:oops'); + try { + runChildrenCLI(['attrs', 'w:oops']); + } catch (e) { + expect(e).toBeInstanceOf(ExitError); + expect(e.code).toBe(2); + } + }); + + it('attrs: empty object → prints "(no attributes)"', () => { + getAttributes.mockReturnValue({}); + runChildrenCLI(['attrs', 'w:t']); + expect(logSpy).toHaveBeenCalledWith('(no attributes)'); + }); + + it('attrs: prints spec lines including use/type/default/fixed/ref when present', () => { + getAttributes.mockReturnValue({ + 'w:val': { use: 'optional', type: 'ST_String' }, + 'w:color': { type: 'ST_HexColor', default: 'auto' }, + 'w:foo': { fixed: 'bar', ref: 'w:bar' }, + 'w:bare': {}, + }); + runChildrenCLI(['attrs', 'w:u']); + + const lines = logSpy.mock.calls.map((c) => c[0]); + + expect(lines).toContain('w:val use=optional type=ST_String'); + expect(lines).toContain('w:color type=ST_HexColor default=auto'); + expect(lines).toContain('w:foo fixed=bar ref=w:bar'); + expect(lines).toContain('w:bare'); + }); + + it('default: prints top-level usage and exits 2 on unknown subcommand', () => { + expect(() => runChildrenCLI(['wat', 'arg1'])).toThrow(ExitError); + const err = errSpy.mock.calls.map((c) => c[0]).join('\n'); + expect(err).toMatch(/Usage:\n\s+ooxml children /); + try { + runChildrenCLI(['wat']); + } catch (e) { + expect(e).toBeInstanceOf(ExitError); + expect(e.code).toBe(2); + } + }); +}); diff --git a/packages/ooxml-inspector/src/children/get-attributes.js b/packages/ooxml-inspector/src/children/get-attributes.js new file mode 100644 index 0000000000..2465123f58 --- /dev/null +++ b/packages/ooxml-inspector/src/children/get-attributes.js @@ -0,0 +1,15 @@ +import { getSchema } from './index.js'; + +/** + * Return attributes map for a QName (e.g. "w:p") + * @param {string} qname + */ +export function getAttributes(qname) { + const schema = getSchema(); + const entry = schema.elements[qname]; + if (!entry) return null; + + const attrs = entry.attributes || {}; + // stable sort for predictable CLI output + return Object.fromEntries(Object.entries(attrs).sort(([a], [b]) => a.localeCompare(b))); +} diff --git a/packages/ooxml-inspector/src/children/get-attributes.test.js b/packages/ooxml-inspector/src/children/get-attributes.test.js new file mode 100644 index 0000000000..d64a7a1a7a --- /dev/null +++ b/packages/ooxml-inspector/src/children/get-attributes.test.js @@ -0,0 +1,95 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; + +const H = vi.hoisted(() => ({ + getSchema: vi.fn(), +})); + +// Mock the module that provides getSchema BEFORE importing the SUT +vi.mock('./index.js', () => ({ + getSchema: H.getSchema, +})); + +import { getAttributes } from './get-attributes.js'; + +beforeEach(() => { + vi.clearAllMocks(); +}); + +describe('getAttributes(qname)', () => { + it('returns null when element entry is missing', () => { + H.getSchema.mockReturnValueOnce({ elements: {} }); + + const out = getAttributes('w:missing'); + expect(H.getSchema).toHaveBeenCalledTimes(1); + expect(out).toBeNull(); + }); + + it('returns {} when attributes are missing on the element', () => { + H.getSchema.mockReturnValueOnce({ + elements: { + 'w:p': { children: [] }, // no attributes field + }, + }); + + const out = getAttributes('w:p'); + expect(H.getSchema).toHaveBeenCalledTimes(1); + expect(out).toEqual({}); + }); + + it('returns a sorted copy of the attributes by key (stable/predictable order)', () => { + // Intentionally unsorted keys + const attrs = { + 'w:zeta': { type: 'xs:string' }, + 'w:alpha': { type: 'xs:string' }, + 'w:mid': { type: 'xs:int' }, + }; + + H.getSchema.mockReturnValueOnce({ + elements: { + 'w:p': { attributes: attrs }, + }, + }); + + const out = getAttributes('w:p'); + expect(out).toEqual({ + 'w:alpha': { type: 'xs:string' }, + 'w:mid': { type: 'xs:int' }, + 'w:zeta': { type: 'xs:string' }, + }); + + // Returned object should not be the same reference as the source attrs + expect(out).not.toBe(attrs); + }); + + it('preserves attribute values while only reordering keys', () => { + const attrs = { + 'w:c': { type: 'xs:boolean', use: 'optional' }, + 'w:a': { type: 'xs:string', default: 'x' }, + 'w:b': { type: 'xs:int', fixed: 3 }, + }; + + H.getSchema.mockReturnValueOnce({ + elements: { + 'w:rPr': { attributes: attrs }, + }, + }); + + const out = getAttributes('w:rPr'); + // Same entries, sorted by key + expect(Object.keys(out)).toEqual(['w:a', 'w:b', 'w:c']); + expect(out['w:a']).toEqual({ type: 'xs:string', default: 'x' }); + expect(out['w:b']).toEqual({ type: 'xs:int', fixed: 3 }); + expect(out['w:c']).toEqual({ type: 'xs:boolean', use: 'optional' }); + }); + + // it('does not blow up with empty schema or missing elements key', () => { + // H.getSchema + // .mockReturnValueOnce({}) + // .mockReturnValueOnce({ elements: null }) + // .mockReturnValueOnce({ elements: undefined }); + + // expect(getAttributes('w:x')).toBeNull(); + // expect(getAttributes('w:x')).toBeNull(); + // expect(getAttributes('w:x')).toBeNull(); + // }); +}); diff --git a/packages/ooxml-inspector/src/children/get-children.js b/packages/ooxml-inspector/src/children/get-children.js new file mode 100644 index 0000000000..c1d0500240 --- /dev/null +++ b/packages/ooxml-inspector/src/children/get-children.js @@ -0,0 +1,42 @@ +import { allowedChildren, hasElement, getSchema } from './index.js'; + +export const getChildren = (element) => { + console.debug(`Getting children for element: ${element}`); + if (!element) { + console.error('Error: Element name required'); + console.log('Usage: node bin/ooxml children '); + process.exit(1); + } + + try { + const children = allowedChildren(element); + if (children.length === 0) { + if (hasElement(element)) { + console.log(`${element} has no children (leaf element or simple content)`); + } else { + console.log(`Element ${element} not found in schema`); + + // Try to suggest similar elements + const { elements } = getSchema(); + const allElements = Object.keys(elements); + const prefix = element.split(':')[0]; + const similar = allElements.filter((el) => el.startsWith(prefix + ':')).slice(0, 5); + if (similar.length > 0) { + console.log('\nDid you mean one of these?'); + similar.forEach((el) => console.log(` - ${el}`)); + } + } + } else { + console.log(`Allowed children for ${element}:`); + children.forEach((child) => console.log(` - ${child}`)); + console.log(`\nTotal: ${children.length} allowed children`); + } + } catch (err) { + if (err.message.includes('No schema JSON found')) { + console.error('Error: Schema not found. Run generator first:'); + console.log(' node bin/ooxml'); + } else { + throw err; + } + } +}; diff --git a/packages/ooxml-inspector/src/children/get-children.test.js b/packages/ooxml-inspector/src/children/get-children.test.js new file mode 100644 index 0000000000..71c70928dd --- /dev/null +++ b/packages/ooxml-inspector/src/children/get-children.test.js @@ -0,0 +1,126 @@ +import { describe, it, beforeEach, afterEach, expect, vi } from 'vitest'; + +vi.mock('./index.js', () => ({ + allowedChildren: vi.fn(), + hasElement: vi.fn(), + getSchema: vi.fn(), +})); + +import { allowedChildren, hasElement, getSchema } from './index.js'; +import { getChildren } from './get-children.js'; + +describe('getChildren CLI helper', () => { + let logSpy, errorSpy, exitSpy; + + beforeEach(() => { + // fresh mocks per test + vi.clearAllMocks(); + // capture console + logSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); + errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + // prevent the real process.exit from killing the test run + exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => {}); + }); + + afterEach(() => { + logSpy.mockRestore(); + errorSpy.mockRestore(); + exitSpy.mockRestore(); + }); + + it('exits with usage when no element is provided', async () => { + // Make exit actually stop execution + const exitSpy = vi.spyOn(process, 'exit').mockImplementation(() => { + throw new Error('__EXIT__'); + }); + const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); + const errorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + // Mocks to ensure we don't accidentally continue + const { allowedChildren } = await import('./index.js'); + + expect(() => getChildren(undefined)).toThrow('__EXIT__'); + + expect(errorSpy).toHaveBeenCalledWith('Error: Element name required'); + expect(logSpy).toHaveBeenCalledWith('Usage: node bin/ooxml children '); + expect(allowedChildren).not.toHaveBeenCalled(); + + exitSpy.mockRestore(); + logSpy.mockRestore(); + errorSpy.mockRestore(); + }); + + it('prints allowed children and total when children exist', () => { + allowedChildren.mockReturnValue(['w:r', 'w:p']); + getChildren('w:body'); + + expect(logSpy).toHaveBeenCalledWith('Allowed children for w:body:'); + expect(logSpy).toHaveBeenCalledWith(' - w:r'); + expect(logSpy).toHaveBeenCalledWith(' - w:p'); + expect(logSpy).toHaveBeenCalledWith('\nTotal: 2 allowed children'); + expect(errorSpy).not.toHaveBeenCalled(); + expect(exitSpy).not.toHaveBeenCalled(); + }); + + it('prints leaf/simple-content message when element exists but has no children', () => { + allowedChildren.mockReturnValue([]); + hasElement.mockReturnValue(true); + + getChildren('w:t'); + + expect(logSpy).toHaveBeenCalledWith('w:t has no children (leaf element or simple content)'); + expect(errorSpy).not.toHaveBeenCalled(); + expect(exitSpy).not.toHaveBeenCalled(); + }); + + it('prints "not found" and up to 5 suggestions for same prefix when element is unknown', () => { + allowedChildren.mockReturnValue([]); + hasElement.mockReturnValue(false); + // Elements order matters for slice(0, 5) + getSchema.mockReturnValue({ + elements: { + 'w:p': [], + 'w:para': [], + 'w:r': [], + 'a:blip': [], + 'w:tbl': [], + 'w:tr': [], + 'w:tc': [], + }, + }); + + getChildren('w:oops'); + + expect(logSpy).toHaveBeenCalledWith('Element w:oops not found in schema'); + // "Did you mean one of these?" header should appear + expect(logSpy).toHaveBeenCalledWith('\nDid you mean one of these?'); + + // collect all console.log calls and count suggestion lines + const suggestionLines = logSpy.mock.calls.map((args) => args.join(' ')).filter((line) => line.startsWith(' - ')); + + // Only the first 5 "w:" keys should be listed + expect(suggestionLines).toEqual([' - w:p', ' - w:para', ' - w:r', ' - w:tbl', ' - w:tr']); + + expect(errorSpy).not.toHaveBeenCalled(); + expect(exitSpy).not.toHaveBeenCalled(); + }); + + it('handles "No schema JSON found" by printing guidance (no throw)', () => { + allowedChildren.mockImplementation(() => { + throw new Error('No schema JSON found at dist/schema.transitional.json'); + }); + + expect(() => getChildren('w:p')).not.toThrow(); + expect(errorSpy).toHaveBeenCalledWith('Error: Schema not found. Run generator first:'); + expect(logSpy).toHaveBeenCalledWith(' node bin/ooxml'); + expect(exitSpy).not.toHaveBeenCalled(); + }); + + it('rethrows unexpected errors', () => { + allowedChildren.mockImplementation(() => { + throw new Error('boom'); + }); + expect(() => getChildren('w:p')).toThrow(/boom/); + expect(exitSpy).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/ooxml-inspector/src/children/index.js b/packages/ooxml-inspector/src/children/index.js new file mode 100644 index 0000000000..393dbd032f --- /dev/null +++ b/packages/ooxml-inspector/src/children/index.js @@ -0,0 +1,5 @@ +export * from './get-children.js'; +export * from './lookup.js'; +export * from './schema.js'; +export * from './cli.js'; +export * from './get-attributes.js'; diff --git a/packages/ooxml-inspector/src/children/lookup.js b/packages/ooxml-inspector/src/children/lookup.js new file mode 100644 index 0000000000..810c951e67 --- /dev/null +++ b/packages/ooxml-inspector/src/children/lookup.js @@ -0,0 +1,256 @@ +import { getSchema, loadSchemaSync } from './schema.js'; + +/** + * @typedef {Object} SchemaOptions + * @property {string} [schemaPath] - Path to schema file + * @property {boolean} [cache] - Whether to cache schema + */ + +/** + * @typedef {Object} ElementDefinition + * @property {string[]} [children] - Array of allowed child element qualified names + * @property {Object} [attributes] - Allowed attributes for this element + */ + +/** + * @typedef {Object} Schema + * @property {Object.} elements - Map of qualified names to element definitions + * @property {Object.} namespaces - Map of namespace URIs to prefixes + */ + +/** + * @typedef {Object} ValidationResult + * @property {boolean} ok - Whether validation passed + * @property {string[]} invalid - Array of invalid child qualified names + */ + +/** + * @typedef {Object} SchemaStats + * @property {number} totalElements - Total number of elements in schema + * @property {number} elementsWithChildren - Number of elements that have children + * @property {number} namespaces - Number of namespaces in schema + * @property {Object.} byNamespace - Count of elements by namespace prefix + */ + +/** + * @typedef {Object} AllTagsOptions + * @property {string|null} [prefix=null] - Filter by namespace prefix + * @property {boolean|null} [hasChildren=null] - Filter by whether elements have children + */ + +/** + * Extracts the namespace prefix from a qualified name. + * + * @param {string} qname - The qualified name (e.g., 'html:div' or 'svg:circle') + * @returns {string} The namespace prefix, or empty string if no prefix exists + * + * @example + * getPrefix('html:div'); // returns 'html' + * getPrefix('div'); // returns '' + */ +export function getPrefix(qname) { + const i = qname.indexOf(':'); + return i > 0 ? qname.slice(0, i) : ''; +} + +/** + * Extracts the local name from a qualified name. + * + * @param {string} qname - The qualified name (e.g., 'html:div' or 'svg:circle') + * @returns {string} The local name part of the qualified name + * + * @example + * getLocalName('html:div'); // returns 'div' + * getLocalName('div'); // returns 'div' + */ +export function getLocalName(qname) { + const i = qname.indexOf(':'); + return i > 0 ? qname.slice(i + 1) : qname; +} + +/** + * Gets the list of allowed child elements for a given parent element. + * + * @param {string} qname - The qualified name of the parent element + * @param {SchemaOptions} [opts] - Schema loading options + * @returns {string[]} Array of qualified names of allowed child elements + * + * @example + * allowedChildren('html:ul', opts); // returns ['html:li'] + */ +export function allowedChildren(qname, opts) { + const { elements } = getSchema(opts); + const def = elements?.[qname]; + return def?.children ?? []; +} + +/** + * Checks if a child element is allowed under a parent element. + * + * @param {string} parent - The qualified name of the parent element + * @param {string} child - The qualified name of the child element + * @param {SchemaOptions} [opts] - Schema loading options + * @returns {boolean} True if the child is allowed under the parent + * + * @example + * isAllowedChild('html:ul', 'html:li', opts); // returns true + * isAllowedChild('html:ul', 'html:div', opts); // returns false + */ +export function isAllowedChild(parent, child, opts) { + const kids = allowedChildren(parent, opts); + return kids.includes(child); +} + +/** + * Validates a list of child elements against a parent element's allowed children. + * Performs a shallow validation check. + * + * @param {string} parent - The qualified name of the parent element + * @param {string[]} childList - Array of qualified names of child elements to validate + * @param {SchemaOptions} [opts] - Schema loading options + * @returns {ValidationResult} Validation result with ok status and invalid children + * + * @example + * validateChildren('html:ul', ['html:li', 'html:div'], opts); + * // returns { ok: false, invalid: ['html:div'] } + */ +export function validateChildren(parent, childList, opts) { + const allowed = new Set(allowedChildren(parent, opts)); + const invalid = childList.filter((c) => !allowed.has(c)); + return { ok: invalid.length === 0, invalid }; +} + +/** + * Gets all elements that belong to a specific namespace. + * + * @param {string} namespace - The namespace URI to filter by + * @param {SchemaOptions} [opts] - Schema loading options + * @returns {string[]} Array of local names (without prefix) of elements in the namespace + * + * @example + * getElementsByNamespace('http://www.w3.org/1999/xhtml', opts); + * // returns ['div', 'span', 'p', ...] + */ +export function getElementsByNamespace(namespace, opts) { + const { elements, namespaces } = getSchema(opts); + const prefix = namespaces[namespace]; + if (!prefix) return []; + return Object.keys(elements) + .filter((qn) => qn.startsWith(prefix + ':')) + .map(getLocalName); +} + +/** + * Checks if an element exists in the schema. + * + * @param {string} qname - The qualified name of the element to check + * @param {SchemaOptions} [opts] - Schema loading options + * @returns {boolean} True if the element exists in the schema + * + * @example + * hasElement('html:div', opts); // returns true + * hasElement('fake:element', opts); // returns false + */ +export function hasElement(qname, opts) { + const { elements } = getSchema(opts); + return Object.prototype.hasOwnProperty.call(elements, qname); +} + +/** + * Generates statistics about the loaded schema. + * + * @param {SchemaOptions} [opts] - Schema loading options + * @returns {SchemaStats} Object containing various statistics about the schema + * + * @example + * getSchemaStats(opts); + * // returns { + * // totalElements: 150, + * // elementsWithChildren: 75, + * // namespaces: 3, + * // byNamespace: { 'html': 120, 'svg': 25, 'math': 5 } + * // } + */ +export function getSchemaStats(opts) { + const { elements, namespaces } = getSchema(opts); + const stats = { + totalElements: Object.keys(elements).length, + elementsWithChildren: 0, + namespaces: Object.keys(namespaces).length, + byNamespace: {}, + }; + + for (const [qname, def] of Object.entries(elements)) { + if ((def?.children?.length ?? 0) > 0) stats.elementsWithChildren++; + const pfx = getPrefix(qname); + if (pfx) stats.byNamespace[pfx] = (stats.byNamespace[pfx] || 0) + 1; + // note: attributes available at def.attributes if you need them elsewhere + } + + return stats; +} + +/** + * Gets the allowed child elements for a given element using synchronous schema loading. + * + * @param {string} qname - The qualified name of the parent element + * @returns {string[]} Array of qualified names of allowed child elements + * + * @example + * childrenOf('html:ul'); // returns ['html:li'] + */ +export function childrenOf(qname) { + const { elements } = loadSchemaSync(); + return elements?.[qname]?.children ?? []; +} + +/** + * Gets all element tags from the schema with optional filtering. + * Uses synchronous schema loading. + * + * @param {AllTagsOptions} [options={}] - Filtering options + * @param {string|null} [options.prefix=null] - Filter by namespace prefix (with or without colon) + * @param {boolean|null} [options.hasChildren=null] - Filter by whether elements have children + * @returns {string[]} Sorted array of qualified element names matching the filters + * + * @example + * allTags(); // returns all tags + * allTags({ prefix: 'html' }); // returns only HTML tags + * allTags({ hasChildren: true }); // returns only tags that can have children + * allTags({ prefix: 'svg', hasChildren: false }); // returns SVG leaf elements + */ +export function allTags({ prefix = null, hasChildren = null } = {}) { + const { elements } = loadSchemaSync(); + let tags = Object.keys(elements).sort(); + + if (prefix) { + const p = prefix.endsWith(':') ? prefix : `${prefix}:`; + tags = tags.filter((t) => t.startsWith(p)); + } + + if (hasChildren !== null) { + tags = tags.filter((t) => { + const n = elements[t]?.children?.length ?? 0; + return hasChildren ? n > 0 : n === 0; + }); + } + + return tags; +} + +/** + * Gets all namespace mappings from the schema. + * Uses synchronous schema loading. + * + * @returns {Object.} Object mapping namespace URIs to prefixes + * + * @example + * namespaces(); + * // returns { + * // 'http://www.w3.org/1999/xhtml': 'html', + * // 'http://www.w3.org/2000/svg': 'svg' + * // } + */ +export function namespaces() { + return loadSchemaSync().namespaces; +} diff --git a/packages/ooxml-inspector/src/children/lookup.test.js b/packages/ooxml-inspector/src/children/lookup.test.js new file mode 100644 index 0000000000..8a31528350 --- /dev/null +++ b/packages/ooxml-inspector/src/children/lookup.test.js @@ -0,0 +1,250 @@ +import { describe, it, expect, beforeEach, vi } from 'vitest'; + +vi.mock('./schema.js', () => { + return { + getSchema: vi.fn(), + loadSchemaSync: vi.fn(), + }; +}); + +import { + getPrefix, + getLocalName, + allowedChildren, + isAllowedChild, + validateChildren, + getElementsByNamespace, + hasElement, + getSchemaStats, + childrenOf, + allTags, + namespaces, +} from './lookup.js'; + +import { getSchema, loadSchemaSync } from './schema.js'; + +const makeSchema = (overrides = {}) => ({ + elements: { + 'html:ul': { children: ['html:li'] }, + 'html:li': { children: [] }, + 'html:div': { children: ['html:span', 'html:div'] }, + 'html:span': { children: [] }, + 'svg:svg': { children: ['svg:g', 'svg:rect'] }, + 'svg:g': { children: [] }, + 'svg:rect': { children: [] }, + 'math:math': { children: [] }, + nopfx: { children: ['nopfx-child'] }, // demonstrates no prefix + 'nopfx-child': { children: [] }, + // element with attributes but no children array: + 'html:img': { attributes: { src: 'string' } }, + ...overrides.elements, + }, + namespaces: { + 'http://www.w3.org/1999/xhtml': 'html', + 'http://www.w3.org/2000/svg': 'svg', + 'http://www.w3.org/1998/Math/MathML': 'math', + ...overrides.namespaces, + }, +}); + +describe('lookup helpers', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('getPrefix', () => { + it('returns prefix when present', () => { + expect(getPrefix('html:div')).toBe('html'); + expect(getPrefix('svg:rect')).toBe('svg'); + }); + it('returns empty string when no colon', () => { + expect(getPrefix('div')).toBe(''); + expect(getPrefix('')).toBe(''); + }); + }); + + describe('getLocalName', () => { + it('returns local part with prefix', () => { + expect(getLocalName('html:div')).toBe('div'); + expect(getLocalName('svg:rect')).toBe('rect'); + }); + it('returns whole string when no prefix', () => { + expect(getLocalName('div')).toBe('div'); + }); + }); + + describe('allowedChildren', () => { + it('returns children array when present', () => { + const schema = makeSchema(); + getSchema.mockReturnValue(schema); + expect(allowedChildren('html:ul')).toEqual(['html:li']); + expect(allowedChildren('html:div')).toEqual(['html:span', 'html:div']); + }); + it('returns empty array when element not found', () => { + getSchema.mockReturnValue(makeSchema()); + expect(allowedChildren('html:table')).toEqual([]); + }); + it('returns empty array when element has no children array', () => { + getSchema.mockReturnValue(makeSchema()); + expect(allowedChildren('html:img')).toEqual([]); + }); + }); + + describe('isAllowedChild', () => { + it('true for valid child; false otherwise', () => { + getSchema.mockReturnValue(makeSchema()); + expect(isAllowedChild('html:ul', 'html:li')).toBe(true); + expect(isAllowedChild('html:ul', 'html:div')).toBe(false); + expect(isAllowedChild('html:img', 'html:span')).toBe(false); + }); + }); + + describe('validateChildren', () => { + it('flags invalid children only', () => { + getSchema.mockReturnValue(makeSchema()); + const res = validateChildren('html:div', ['html:span', 'html:div', 'html:li']); + expect(res.ok).toBe(false); + expect(res.invalid).toEqual(['html:li']); + }); + it('ok when all valid', () => { + getSchema.mockReturnValue(makeSchema()); + const res = validateChildren('html:ul', ['html:li']); + expect(res.ok).toBe(true); + expect(res.invalid).toEqual([]); + }); + it('ok when no children to check', () => { + getSchema.mockReturnValue(makeSchema()); + const res = validateChildren('html:img', []); + expect(res.ok).toBe(true); + expect(res.invalid).toEqual([]); + }); + }); + + describe('getElementsByNamespace', () => { + it('returns local names for matching namespace', () => { + getSchema.mockReturnValue(makeSchema()); + const out = getElementsByNamespace('http://www.w3.org/2000/svg'); + // svg elements present: svg, g, rect + expect(out.sort()).toEqual(['g', 'rect', 'svg']); + }); + it('returns empty for unknown namespace', () => { + getSchema.mockReturnValue(makeSchema()); + expect(getElementsByNamespace('http://unknown/')).toEqual([]); + }); + it('handles no elements gracefully', () => { + getSchema.mockReturnValue({ elements: {}, namespaces: { x: 'x' } }); + expect(getElementsByNamespace('x')).toEqual([]); + }); + }); + + describe('hasElement', () => { + it('true when element exists', () => { + getSchema.mockReturnValue(makeSchema()); + expect(hasElement('html:ul')).toBe(true); + }); + it('false when element missing', () => { + getSchema.mockReturnValue(makeSchema()); + expect(hasElement('html:table')).toBe(false); + }); + }); + + describe('getSchemaStats', () => { + it('computes totals, elementsWithChildren, namespaces, and byNamespace', () => { + const schema = makeSchema(); + getSchema.mockReturnValue(schema); + + const s = getSchemaStats(); + // total elements is count of keys in elements + expect(s.totalElements).toBe(Object.keys(schema.elements).length); + + // elements with children > 0 + const expectedWithChildren = Object.values(schema.elements).filter( + (def) => (def.children?.length ?? 0) > 0, + ).length; + expect(s.elementsWithChildren).toBe(expectedWithChildren); + + // namespaces count is keys in namespaces + expect(s.namespaces).toBe(Object.keys(schema.namespaces).length); + + // byNamespace counts by prefix present in qname + const expectedByNs = {}; + for (const qn of Object.keys(schema.elements)) { + const p = qn.includes(':') ? qn.split(':')[0] : ''; + if (p) expectedByNs[p] = (expectedByNs[p] || 0) + 1; + } + expect(s.byNamespace).toEqual(expectedByNs); + }); + + it('handles empty schema structures', () => { + getSchema.mockReturnValue({ elements: {}, namespaces: {} }); + const s = getSchemaStats(); + expect(s).toEqual({ + totalElements: 0, + elementsWithChildren: 0, + namespaces: 0, + byNamespace: {}, + }); + }); + }); + + describe('childrenOf (sync path)', () => { + it('uses loadSchemaSync and returns children', () => { + const schema = makeSchema(); + loadSchemaSync.mockReturnValue(schema); + expect(childrenOf('svg:svg')).toEqual(['svg:g', 'svg:rect']); + expect(childrenOf('html:img')).toEqual([]); // no children array + expect(childrenOf('missing:el')).toEqual([]); + }); + }); + + describe('allTags (sync path)', () => { + it('returns all tags sorted by default', () => { + const schema = makeSchema(); + loadSchemaSync.mockReturnValue(schema); + const out = allTags(); + const expected = Object.keys(schema.elements).sort(); + expect(out).toEqual(expected); + }); + + it('filters by prefix (with or without colon)', () => { + loadSchemaSync.mockReturnValue(makeSchema()); + const htmlA = allTags({ prefix: 'html' }); + const htmlB = allTags({ prefix: 'html:' }); + expect(htmlA).toEqual(htmlB); + expect(htmlA.every((t) => t.startsWith('html:'))).toBe(true); + }); + + it('filters by hasChildren = true', () => { + loadSchemaSync.mockReturnValue(makeSchema()); + const out = allTags({ hasChildren: true }); + expect(out.length).toBeGreaterThan(0); + expect(out.every((t) => (loadSchemaSync().elements[t]?.children?.length ?? 0) > 0)).toBe(true); + }); + + it('filters by hasChildren = false', () => { + loadSchemaSync.mockReturnValue(makeSchema()); + const out = allTags({ hasChildren: false }); + expect(out.length).toBeGreaterThan(0); + expect(out.every((t) => (loadSchemaSync().elements[t]?.children?.length ?? 0) === 0)).toBe(true); + }); + + it('combines prefix and hasChildren filters', () => { + loadSchemaSync.mockReturnValue(makeSchema()); + const out = allTags({ prefix: 'svg', hasChildren: false }); + expect(out.every((t) => t.startsWith('svg:'))).toBe(true); + expect(out.every((t) => (loadSchemaSync().elements[t]?.children?.length ?? 0) === 0)).toBe(true); + }); + }); + + describe('namespaces (sync path)', () => { + it('returns namespaces from sync schema', () => { + const schema = makeSchema(); + loadSchemaSync.mockReturnValue(schema); + expect(namespaces()).toEqual(schema.namespaces); + }); + it('works with empty namespaces', () => { + loadSchemaSync.mockReturnValue({ elements: {}, namespaces: {} }); + expect(namespaces()).toEqual({}); + }); + }); +}); diff --git a/packages/ooxml-inspector/src/children/schema.js b/packages/ooxml-inspector/src/children/schema.js new file mode 100644 index 0000000000..ee629541b7 --- /dev/null +++ b/packages/ooxml-inspector/src/children/schema.js @@ -0,0 +1,13 @@ +import schemaJson from '../../dist/schema.transitional.json' with { type: 'json' }; + +let CACHE = null; + +/** Return the OOXML schema (bundled JSON). */ +export function getSchema() { + return (CACHE ??= schemaJson); +} + +/** Legacy sync loader: just return the bundled JSON in runtime. */ +export function loadSchemaSync() { + return getSchema(); +} diff --git a/packages/ooxml-inspector/src/cli.js b/packages/ooxml-inspector/src/cli.js new file mode 100644 index 0000000000..7fe28b51b7 --- /dev/null +++ b/packages/ooxml-inspector/src/cli.js @@ -0,0 +1,20 @@ +#!/usr/bin/env node +import { runGenerator } from '../generator/src/index.js'; +import { runChildrenCLI } from './children/index.js'; + +const [, , cmd, ...rest] = process.argv; + +switch (cmd) { + case undefined: + runGenerator(); + break; + case 'children': + case 'tags': + case 'namespaces': + case 'attrs': + runChildrenCLI([cmd, ...rest]); + break; + default: + console.error(`Unknown command: ${cmd}`); + process.exit(2); +} diff --git a/packages/ooxml-inspector/src/index.js b/packages/ooxml-inspector/src/index.js new file mode 100644 index 0000000000..fbef3e3d1f --- /dev/null +++ b/packages/ooxml-inspector/src/index.js @@ -0,0 +1,3 @@ +import { childrenOf } from './children/index.js'; + +export { childrenOf }; diff --git a/packages/ooxml-inspector/tsconfig.json b/packages/ooxml-inspector/tsconfig.json new file mode 100644 index 0000000000..e294c5fde2 --- /dev/null +++ b/packages/ooxml-inspector/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "checkJs": true, + "allowJs": true, + + "module": "NodeNext", + "moduleResolution": "NodeNext", + + "target": "ES2020", + "lib": ["ES2020"], + "types": ["node"], + + "skipLibCheck": true, + "declaration": true, + "emitDeclarationOnly": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "outDir": "dist", + "baseUrl": "." + }, + "exclude": ["node_modules", "dist", "**/*.test.js"] +} diff --git a/packages/ooxml-inspector/vitest.config.js b/packages/ooxml-inspector/vitest.config.js new file mode 100644 index 0000000000..cae1aa6c36 --- /dev/null +++ b/packages/ooxml-inspector/vitest.config.js @@ -0,0 +1,44 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['**/*.test.js'], + environment: 'node', + exclude: [ + 'node_modules/**', + '**/node_modules/**', + '**/dist/**', + 'coverage/**', + '**/example/**', + 'generator/types/**', + ], + coverage: { + provider: 'v8', + reportsDirectory: 'coverage', + reporter: ['text', 'html', 'lcov'], + all: false, + exclude: [ + // always ignore deps + build outputs + 'node_modules/**', + '**/node_modules/**', + '**/dist/**', + '**/*.d.ts', + 'coverage/**', + + // tsup helper assets sometimes appear via dep graph + '**/node_modules/tsup/**', + + // config & metadata + 'vitest.config.*', + '**/constants.js', + + 'packages/**/src/index.js', + 'packages/**/src/cli.js', + + // ignore examples + 'packages/**/example/**', + 'generator/types/**', + ], + }, + }, +}); diff --git a/packages/super-editor/package.json b/packages/super-editor/package.json index 8b62a5977a..89cd078fb4 100644 --- a/packages/super-editor/package.json +++ b/packages/super-editor/package.json @@ -48,6 +48,7 @@ "pack": "rm *.tgz 2>/dev/null || true && npm run build && npm pack && mv harbour-enterprises-super-editor-0.0.1-alpha.0.tgz ./super-editor.tgz" }, "dependencies": { + "@superdoc-dev/ooxml-inspector": "^1.0.0", "color2k": "^2.0.3", "eventemitter3": "^5.0.1", "he": "^1.2.0", diff --git a/packages/super-editor/vite.config.js b/packages/super-editor/vite.config.js index 2dec0ca5cb..d891141a7b 100644 --- a/packages/super-editor/vite.config.js +++ b/packages/super-editor/vite.config.js @@ -85,6 +85,7 @@ export default defineConfig(({ mode }) => { '@packages': fileURLToPath(new URL('../', import.meta.url)), '@converter': fileURLToPath(new URL('./src/core/super-converter', import.meta.url)), '@tests': fileURLToPath(new URL('./src/tests', import.meta.url)), + '@ooxml-inspector': fileURLToPath(new URL('../../../ooxml-inspector/dist/index.js', import.meta.url)) }, extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json'], },