diff --git a/package-lock.json b/package-lock.json index ad8dc739eb..df9810426b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -155,14 +155,14 @@ } }, "node_modules/@ai-sdk/gateway": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-2.0.16.tgz", - "integrity": "sha512-qiIaVs1w1XcNiFG6cjhOwolPuMFSvy6ZxDeLaPlEK/kSmNGfd+gUA2CTpBPWWT3qN6Zxfdrwq+ti4BfkdmLIJQ==", + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-2.0.17.tgz", + "integrity": "sha512-oVAG6q72KsjKlrYdLhWjRO7rcqAR8CjokAbYuyVZoCO4Uh2PH/VzZoxZav71w2ipwlXhHCNaInGYWNs889MMDA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@ai-sdk/provider": "2.0.0", - "@ai-sdk/provider-utils": "3.0.17", + "@ai-sdk/provider-utils": "3.0.18", "@vercel/oidc": "3.0.5" }, "engines": { @@ -186,9 +186,9 @@ } }, "node_modules/@ai-sdk/provider-utils": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.17.tgz", - "integrity": "sha512-TR3Gs4I3Tym4Ll+EPdzRdvo/rc8Js6c4nVhFLuvGLX/Y4V9ZcQMa/HTiYsHEgmYrf1zVi6Q145UEZUfleOwOjw==", + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-3.0.18.tgz", + "integrity": "sha512-ypv1xXMsgGcNKUP+hglKqtdDuMg68nWHucPPAhIENrbFAI+xCHiqPVN8Zllxyv1TNZwGWUghPxJXU+Mqps0YRQ==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -204,14 +204,14 @@ } }, "node_modules/@ai-sdk/react": { - "version": "2.0.103", - "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-2.0.103.tgz", - "integrity": "sha512-r5uagRdTqLXPnUEv7xkUuaHG3sAZ5bvYbzJJlRWfRII7E9JfxyjTFGQirjeXjPJYsV8cUdwM1bEpp/46rsgQQg==", + "version": "2.0.105", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-2.0.105.tgz", + "integrity": "sha512-d/nr3fuAsgLli7g9CcShqME+QdTN3S6vbtyL9ZT8iAWfR0xBKYuNrzX3a89vY49lnbdgAqB65l67hsVNCsmVIg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider-utils": "3.0.17", - "ai": "5.0.103", + "@ai-sdk/provider-utils": "3.0.18", + "ai": "5.0.105", "swr": "^2.2.5", "throttleit": "2.1.0" }, @@ -2951,9 +2951,9 @@ } }, "node_modules/@csstools/postcss-cascade-layers/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -3372,9 +3372,9 @@ } }, "node_modules/@csstools/postcss-is-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -3771,9 +3771,9 @@ } }, "node_modules/@csstools/postcss-scope-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -5803,9 +5803,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5815,7 +5815,7 @@ "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", + "js-yaml": "^4.1.1", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, @@ -8430,9 +8430,9 @@ } }, "node_modules/@lezer/common": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.3.0.tgz", - "integrity": "sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.4.0.tgz", + "integrity": "sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==", "license": "MIT" }, "node_modules/@lezer/css": { @@ -8489,9 +8489,9 @@ } }, "node_modules/@lezer/lr": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.3.tgz", - "integrity": "sha512-yenN5SqAxAPv/qMnpWW0AT7l+SxVrgG+u0tNsRQWqbrz66HIl8DnEbBObvy21J5K7+I1v7gsAnlE2VQ5yYVSeA==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.4.tgz", + "integrity": "sha512-LHL17Mq0OcFXm1pGQssuGTQFPPdxARjKM8f7GA5+sGtHi0K3R84YaSbmche0+RKWHnCsx9asEe5OWOI4FHfe4A==", "license": "MIT", "dependencies": { "@lezer/common": "^1.0.0" @@ -10902,9 +10902,9 @@ } }, "node_modules/@nx/eslint-plugin/node_modules/nx/node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", "dev": true, "license": "ISC", "bin": { @@ -10912,6 +10912,9 @@ }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/@nx/eslint-plugin/node_modules/ora": { @@ -12800,6 +12803,10 @@ "resolved": "packages/php-wasm/cli", "link": true }, + "node_modules/@php-wasm/cli-util": { + "resolved": "packages/php-wasm/cli-util", + "link": true + }, "node_modules/@php-wasm/compile": { "resolved": "packages/php-wasm/compile", "link": true @@ -19528,15 +19535,15 @@ } }, "node_modules/ai": { - "version": "5.0.103", - "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.103.tgz", - "integrity": "sha512-TpaeKAzSFHQkUZ5cwkvGZCzElVDY0W7nJNT9Oq31R30PTmCtU8A5ll4IRm+CmolPSYbpXRHHPkgADxGyqex9eg==", + "version": "5.0.105", + "resolved": "https://registry.npmjs.org/ai/-/ai-5.0.105.tgz", + "integrity": "sha512-waQZAvv44KYzys6S3l25ti2jcSuJnkyWFTliSKy3swASL6w6ttPxJTm80d+v9sLWoIxrqE3OwhTJbweNp065fg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "@ai-sdk/gateway": "2.0.16", + "@ai-sdk/gateway": "2.0.17", "@ai-sdk/provider": "2.0.0", - "@ai-sdk/provider-utils": "3.0.17", + "@ai-sdk/provider-utils": "3.0.18", "@opentelemetry/api": "1.9.0" }, "engines": { @@ -20589,9 +20596,9 @@ } }, "node_modules/bare-fs": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.1.tgz", - "integrity": "sha512-zGUCsm3yv/ePt2PHNbVxjjn0nNB1MkIaR4wOCxJ2ig5pCf5cCVAYJXVhQg/3OhhJV6DB1ts7Hv0oUaElc2TPQg==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.5.2.tgz", + "integrity": "sha512-veTnRzkb6aPHOvSKIOy60KzURfBdUflr5VReI+NSaPL6xf+XLdONQgZgpYvUuZLVQ8dCqxpBAudaOM1+KpAUxw==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -20692,9 +20699,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.8.31", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.31.tgz", - "integrity": "sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==", + "version": "2.8.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.32.tgz", + "integrity": "sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==", "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -23094,9 +23101,9 @@ } }, "node_modules/css-blank-pseudo/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -23168,9 +23175,9 @@ } }, "node_modules/css-has-pseudo/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -23323,9 +23330,9 @@ } }, "node_modules/cssdb": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.4.2.tgz", - "integrity": "sha512-PzjkRkRUS+IHDJohtxkIczlxPPZqRo0nXplsYXOMBRPjcVRjj1W4DfvRgshUYTVuUigU7ptVYkFJQ7abUB0nyg==", + "version": "8.4.3", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-8.4.3.tgz", + "integrity": "sha512-8aaDS5nVqMXmYjlmmJpqlDJosiqbl2NJkYuSFOXR6RTY14qNosMrqT4t7O+EUm+OdduQg3GNI2ZwC03No1Y58Q==", "funding": [ { "type": "opencollective", @@ -34653,9 +34660,9 @@ } }, "node_modules/memfs": { - "version": "4.51.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.51.0.tgz", - "integrity": "sha512-4zngfkVM/GpIhC8YazOsM6E8hoB33NP0BCESPOA6z7qaL6umPJNqkO8CNYaLV2FB2MV6H1O3x2luHHOSqppv+A==", + "version": "4.51.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.51.1.tgz", + "integrity": "sha512-Eyt3XrufitN2ZL9c/uIRMyDwXanLI88h/L3MoWqNY747ha3dMR9dWqp8cRT5ntjZ0U1TNuq4U91ZXK0sMBjYOQ==", "license": "Apache-2.0", "dependencies": { "@jsonjoy.com/json-pack": "^1.11.0", @@ -39976,9 +39983,9 @@ } }, "node_modules/postcss-attribute-case-insensitive/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -40220,9 +40227,9 @@ } }, "node_modules/postcss-custom-selectors/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -40258,9 +40265,9 @@ } }, "node_modules/postcss-dir-pseudo-class/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -40386,9 +40393,9 @@ } }, "node_modules/postcss-focus-visible/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -40424,9 +40431,9 @@ } }, "node_modules/postcss-focus-within/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -40713,9 +40720,9 @@ } }, "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -40741,9 +40748,9 @@ } }, "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -40840,9 +40847,9 @@ } }, "node_modules/postcss-nesting/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -41209,9 +41216,9 @@ } }, "node_modules/postcss-pseudo-class-any-link/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -41302,9 +41309,9 @@ } }, "node_modules/postcss-selector-not/node_modules/postcss-selector-parser": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", - "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -41462,9 +41469,9 @@ } }, "node_modules/prettier": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.0.tgz", - "integrity": "sha512-pBiBj/gjRY9Qpk1b7cDda6Rbwvkaggos779AHQ0Ek/odwDx6xG6DRBxtnp1QmxbuD7pAO8/SQ8vuhtGv9LoLWA==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.3.tgz", + "integrity": "sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==", "dev": true, "license": "MIT", "bin": { @@ -42023,9 +42030,9 @@ } }, "node_modules/react-day-picker": { - "version": "9.11.2", - "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.11.2.tgz", - "integrity": "sha512-TD/xMUGg2oiKX8jUR21MST5pj+7Y36097YtnDHQFlIcZOu3mbLLw2B2JqEByEGrR3HHveWYnKlyls6WqJgohAg==", + "version": "9.11.3", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.11.3.tgz", + "integrity": "sha512-7lD12UvGbkyXqgzbYIGQTbl+x29B9bAf+k0pP5Dcs1evfpKk6zv4EdH/edNc8NxcmCiTNXr2HIYPrSZ3XvmVBg==", "dev": true, "license": "MIT", "dependencies": { @@ -42981,9 +42988,9 @@ } }, "node_modules/react-remove-scroll": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", - "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "dev": true, "license": "MIT", "dependencies": { @@ -46710,9 +46717,9 @@ } }, "node_modules/swr": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.6.tgz", - "integrity": "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.7.tgz", + "integrity": "sha512-ZEquQ82QvalqTxhBVv/DlAg2mbmUjF4UgpPg9wwk4ufb9rQnZXh1iKyyKBqV6bQGu1Ie7L1QwSYO07qFIa1p+g==", "dev": true, "license": "MIT", "dependencies": { @@ -49899,9 +49906,9 @@ } }, "node_modules/webpack-dev-server/node_modules/ipaddr.js": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", - "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", + "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", "license": "MIT", "engines": { "node": ">= 10" @@ -50979,6 +50986,15 @@ "php-wasm-cli": "php-wasm.js" } }, + "packages/php-wasm/cli-util": { + "name": "@php-wasm/cli-util", + "version": "3.0.22", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=20.18.3", + "npm": ">=10.1.0" + } + }, "packages/php-wasm/compile": { "name": "@php-wasm/compile", "version": "0.1.5", diff --git a/packages/php-wasm/cli-util/.eslintrc.json b/packages/php-wasm/cli-util/.eslintrc.json new file mode 100644 index 0000000000..79fd7c1d98 --- /dev/null +++ b/packages/php-wasm/cli-util/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/packages/php-wasm/cli-util/README.md b/packages/php-wasm/cli-util/README.md new file mode 100644 index 0000000000..3ce7246efa --- /dev/null +++ b/packages/php-wasm/cli-util/README.md @@ -0,0 +1,11 @@ +# php-wasm-cli-util + +This library was generated with [Nx](https://nx.dev). + +## Building + +Run `nx build php-wasm-cli-util` to build the library. + +## Running unit tests + +Run `nx test php-wasm-cli-util` to execute the unit tests via [Vitest](https://vitest.dev). diff --git a/packages/php-wasm/cli-util/package.json b/packages/php-wasm/cli-util/package.json new file mode 100644 index 0000000000..8ff61b0dad --- /dev/null +++ b/packages/php-wasm/cli-util/package.json @@ -0,0 +1,39 @@ +{ + "name": "@php-wasm/cli-util", + "version": "3.0.22", + "description": "Utilities for PHP.wasm related CLIs", + "repository": { + "type": "git", + "url": "https://github.com/WordPress/wordpress-playground" + }, + "homepage": "https://developer.wordpress.org/playground", + "author": "The WordPress contributors", + "exports": { + ".": { + "import": "./index.js", + "require": "./index.cjs" + }, + "./package.json": "./package.json", + "./README.md": "./README.md" + }, + "main": "./index.cjs", + "module": "./index.js", + "type": "module", + "types": "index.d.ts", + "typedoc": { + "entryPoint": "./src/index.ts", + "readmeFile": "./README.md", + "displayName": "@php-wasm/cli-util", + "tsconfig": "./tsconfig.lib.json" + }, + "publishConfig": { + "access": "public", + "directory": "../../../dist/packages/php-wasm/cli-util" + }, + "license": "GPL-2.0-or-later", + "gitHead": "2f8d8f3cea548fbd75111e8659a92f601cddc593", + "engines": { + "node": ">=20.18.3", + "npm": ">=10.1.0" + } +} diff --git a/packages/php-wasm/cli-util/project.json b/packages/php-wasm/cli-util/project.json new file mode 100644 index 0000000000..238fcbe11d --- /dev/null +++ b/packages/php-wasm/cli-util/project.json @@ -0,0 +1,81 @@ +{ + "name": "php-wasm-cli-util", + "$schema": "../../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "packages/php-wasm/cli-util/src", + "projectType": "library", + "targets": { + "build": { + "executor": "nx:noop", + "dependsOn": ["build:README"] + }, + "build:README": { + "executor": "nx:run-commands", + "options": { + "commands": [ + "cp packages/php-wasm/cli-util/README.md dist/packages/php-wasm/cli-util" + ] + }, + "dependsOn": ["build:package-json"] + }, + "build:package-json": { + "executor": "@wp-playground/nx-extensions:package-json", + "options": { + "tsConfig": "packages/php-wasm/cli-util/tsconfig.lib.json", + "outputPath": "dist/packages/php-wasm/cli-util", + "buildTarget": "php-wasm-cli-util:build:bundle:production" + } + }, + "build:bundle": { + "executor": "@nx/vite:build", + "outputs": ["{options.outputPath}"], + "options": { + "emptyOutDir": false, + "outputPath": "dist/packages/php-wasm/cli-util" + } + }, + "publish": { + "executor": "nx:run-commands", + "options": { + "command": "node tools/scripts/publish.mjs php-wasm-cli-util {args.ver} {args.tag}" + }, + "dependsOn": ["build"] + }, + "package-for-self-hosting": { + "executor": "@wp-playground/nx-extensions:package-for-self-hosting", + "dependsOn": ["build"] + }, + "lint": { + "executor": "@nx/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "useFlatConfig": false, + "lintFilePatterns": ["packages/php-wasm/cli-util/**/*.ts"], + "maxWarnings": 0 + } + }, + "test": { + "executor": "@nx/vite:test", + "outputs": ["{workspaceRoot}/coverage/packages/php-wasm/cli-util"], + "options": { + "reportsDirectory": "../../../coverage/packages/php-wasm/cli-util" + } + }, + "test:esmcjs": { + "executor": "@wp-playground/nx-extensions:assert-built-esm-and-cjs", + "options": { + "outputPath": "dist/packages/php-wasm/cli-util" + }, + "dependsOn": ["build"] + }, + "typecheck": { + "executor": "nx:run-commands", + "options": { + "commands": [ + "tsc -p packages/php-wasm/cli-util/tsconfig.lib.json --noEmit", + "tsc -p packages/php-wasm/cli-util/tsconfig.spec.json --noEmit" + ] + } + } + }, + "tags": ["scope:independent-from-php-binaries"] +} diff --git a/packages/php-wasm/cli-util/src/index.ts b/packages/php-wasm/cli-util/src/index.ts new file mode 100644 index 0000000000..f41a696fd2 --- /dev/null +++ b/packages/php-wasm/cli-util/src/index.ts @@ -0,0 +1 @@ +export * from './lib'; diff --git a/packages/php-wasm/cli-util/src/lib/index.ts b/packages/php-wasm/cli-util/src/lib/index.ts new file mode 100644 index 0000000000..7ad538c9ef --- /dev/null +++ b/packages/php-wasm/cli-util/src/lib/index.ts @@ -0,0 +1,2 @@ +export * from './mounts'; +export * from './xdebug-path-mappings'; diff --git a/packages/php-wasm/cli-util/src/lib/mounts.ts b/packages/php-wasm/cli-util/src/lib/mounts.ts new file mode 100644 index 0000000000..a74bb02754 --- /dev/null +++ b/packages/php-wasm/cli-util/src/lib/mounts.ts @@ -0,0 +1,4 @@ +export interface Mount { + hostPath: string; + vfsPath: string; +} diff --git a/packages/playground/cli/src/xdebug-path-mappings.ts b/packages/php-wasm/cli-util/src/lib/xdebug-path-mappings.ts similarity index 91% rename from packages/playground/cli/src/xdebug-path-mappings.ts rename to packages/php-wasm/cli-util/src/lib/xdebug-path-mappings.ts index 391f0d4371..73dba0273a 100644 --- a/packages/playground/cli/src/xdebug-path-mappings.ts +++ b/packages/php-wasm/cli-util/src/lib/xdebug-path-mappings.ts @@ -1,16 +1,16 @@ import fs from 'fs'; import path from 'path'; -import { type Mount } from './mounts'; +import type { Mount } from './mounts'; import { type X2jOptions, type XmlBuilderOptions, XMLParser, XMLBuilder, } from 'fast-xml-parser'; -import JSONC from 'jsonc-parser'; +import * as JSONC from 'jsonc-parser'; /** - * Create a symlink to temp dir for the Playground CLI. + * Create a symlink to a tempory directory. * * The symlink is created to access the system temp dir * inside the current debugging directory. @@ -18,7 +18,7 @@ import JSONC from 'jsonc-parser'; * @param nativeDirPath The system temp dir path. * @param symlinkPath The symlink name. */ -export async function createPlaygroundCliTempDirSymlink( +export async function createTempDirSymlink( nativeDirPath: string, symlinkPath: string, platform: string @@ -26,19 +26,19 @@ export async function createPlaygroundCliTempDirSymlink( const type = platform === 'win32' ? // On Windows, creating a 'dir' symlink can require elevated permissions. - // In this case, let's make junction points because they function like - // symlinks and do not require elevated permissions. - 'junction' + // In this case, let's make junction points because they function like + // symlinks and do not require elevated permissions. + 'junction' : 'dir'; fs.symlinkSync(nativeDirPath, symlinkPath, type); } /** - * Remove the temp dir symlink if it exists. + * Remove the given temporary directory symlink if it exists. * * @param symlinkPath The symlink path. */ -export async function removePlaygroundCliTempDirSymlink(symlinkPath: string) { +export async function removeTempDirSymlink(symlinkPath: string) { try { const stats = fs.lstatSync(symlinkPath); if (stats.isSymbolicLink()) { @@ -52,7 +52,7 @@ export async function removePlaygroundCliTempDirSymlink(symlinkPath: string) { /** * Filters out mounts that are not in the current working directory * - * @param mounts The Playground CLI mount options. + * @param mounts The mounts list. */ function filterLocalMounts(cwd: string, mounts: Mount[]) { return mounts.filter((mount) => { @@ -91,7 +91,7 @@ export type IDEConfig = { /** * The mounts to consider for debugger path mapping. */ - mounts: Mount[]; + mounts?: Mount[]; /** * The IDE key to use for the debug configuration. Defaults to 'PLAYGROUNDCLI'. */ @@ -137,7 +137,7 @@ type VSCodeConfigNode = { type: string; request: string; port: number; - pathMappings: VSCodeConfigMetaData; + pathMappings?: VSCodeConfigMetaData; }; const xmlParserOptions: X2jOptions = { @@ -170,7 +170,7 @@ export type PhpStormConfigOptions = { host: string; port: number; projectDir: string; - mappings: Mount[]; + mappings?: Mount[]; ideKey: string; }; @@ -201,19 +201,7 @@ export function updatePhpStormConfig( // Create the server element with path mappings const serverElement: PhpStormConfigNode = { - server: [ - { - path_mappings: mappings.map((mapping) => ({ - mapping: [], - ':@': { - 'local-root': `$PROJECT_DIR$/${toPosixPath( - path.relative(options.projectDir, mapping.hostPath) - )}`, - 'remote-root': mapping.vfsPath, - }, - })), - }, - ], + server: [{}], ':@': { name, // NOTE: PhpStorm quirk: Xdebug only works when the full URL (including port) @@ -224,6 +212,18 @@ export function updatePhpStormConfig( }, }; + if (mappings && mappings.length) { + serverElement.server![0].path_mappings = mappings.map((mapping) => ({ + mapping: [], + ':@': { + 'local-root': `$PROJECT_DIR$/${toPosixPath( + path.relative(options.projectDir, mapping.hostPath) + )}`, + 'remote-root': mapping.vfsPath, + }, + })); + } + // Find or create project element let projectElement = config?.find((c: PhpStormConfigNode) => !!c?.project); if (projectElement) { @@ -364,7 +364,7 @@ export function updatePhpStormConfig( export type VSCodeConfigOptions = { name: string; workspaceDir: string; - mappings: Mount[]; + mappings?: Mount[]; }; /** @@ -408,7 +408,8 @@ export function updateVSCodeConfig( // Check if configuration already exists const configurationIndex = configurationsNode?.children?.findIndex( - (child) => JSONC.findNodeAtLocation(child, ['name'])?.value === name + (child: any) => + JSONC.findNodeAtLocation(child, ['name'])?.value === name ); // Only add configuration if it doesn't exist @@ -418,13 +419,16 @@ export function updateVSCodeConfig( type: 'php', request: 'launch', port: 9003, - pathMappings: mappings.reduce((acc, mount) => { + }; + + if (mappings && mappings.length) { + configuration.pathMappings = mappings.reduce((acc, mount) => { acc[mount.vfsPath] = `\${workspaceFolder}/${toPosixPath( path.relative(options.workspaceDir, mount.hostPath) )}`; return acc; - }, {} as VSCodeConfigMetaData), - }; + }, {} as VSCodeConfigMetaData); + } // Get the current length to append at the end const currentLength = configurationsNode?.children?.length || 0; @@ -452,7 +456,7 @@ export function updateVSCodeConfig( * Implement necessary parameters and path mappings in IDE configuration files. * * @param name The configuration name. - * @param mounts The Playground CLI mount options. + * @param mounts The mounts options. */ export async function addXdebugIDEConfig({ name, @@ -461,10 +465,10 @@ export async function addXdebugIDEConfig({ port, cwd, mounts, - ideKey = 'PLAYGROUNDCLI', + ideKey = 'PHPWASMCLI', }: IDEConfig) { - const mappings = filterLocalMounts(cwd, mounts); - const modifiedConfig: string[] = []; + const mappings = mounts ? filterLocalMounts(cwd, mounts) : []; + const modifiedConfig: Record = {}; // PHPstorm if (ides.includes('phpstorm')) { @@ -500,9 +504,8 @@ export async function addXdebugIDEConfig({ ideKey, }); fs.writeFileSync(phpStormConfigFilePath, updatedXml); + modifiedConfig['phpstorm'] = phpStormRelativeConfigFilePath; } - - modifiedConfig.push(phpStormRelativeConfigFilePath); } // VSCode @@ -539,7 +542,7 @@ export async function addXdebugIDEConfig({ // Only write and track the file if changes were made if (updatedJson !== content) { fs.writeFileSync(vsCodeConfigFilePath, updatedJson); - modifiedConfig.push(vsCodeRelativeConfigFilePath); + modifiedConfig['vscode'] = vsCodeRelativeConfigFilePath; } } } @@ -626,7 +629,8 @@ export async function clearXdebugIDEConfig(name: string, cwd: string) { ]); const configurationIndex = configurationsNode?.children?.findIndex( - (child) => JSONC.findNodeAtLocation(child, ['name'])?.value === name + (child: any) => + JSONC.findNodeAtLocation(child, ['name'])?.value === name ); if (configurationIndex !== undefined && configurationIndex >= 0) { @@ -682,8 +686,8 @@ function jsoncApplyEdits(content: string, edits: JSONC.Edit[]) { (edit) => `At ${edit.offset}:${edit.length} - (${edit.content})` ); throw new Error( - `VS Code configuration file (.vscode/launch.json) is not valid a JSONC after Playground CLI modifications. This is likely ` + - `a Playground CLI bug. Please report it at https://github.com/WordPress/wordpress-playground/issues and include the contents ` + + `VS Code configuration file (.vscode/launch.json) is not valid a JSONC after CLI modifications. This is likely ` + + `a CLI bug. Please report it at https://github.com/WordPress/wordpress-playground/issues and include the contents ` + `of your ".vscode/launch.json" file. \n\n Applied edits: ${formattedEdits.join( '\n' )}\n\n The errors are: ${formattedErrors.join('\n')}` diff --git a/packages/playground/cli/tests/xdebug-path-mappings.spec.ts b/packages/php-wasm/cli-util/src/test/xdebug-path-mappings.spec.ts similarity index 94% rename from packages/playground/cli/tests/xdebug-path-mappings.spec.ts rename to packages/php-wasm/cli-util/src/test/xdebug-path-mappings.spec.ts index 0e03fed0b2..0485d66858 100644 --- a/packages/playground/cli/tests/xdebug-path-mappings.spec.ts +++ b/packages/php-wasm/cli-util/src/test/xdebug-path-mappings.spec.ts @@ -3,7 +3,7 @@ import { updateVSCodeConfig, type PhpStormConfigOptions, type VSCodeConfigOptions, -} from '../src/xdebug-path-mappings'; +} from '../lib/xdebug-path-mappings'; import { XMLParser } from 'fast-xml-parser'; import * as JSONC from 'jsonc-parser'; @@ -99,7 +99,7 @@ describe('updatePhpStormConfig', () => { vfsPath: '/var/www/html/src', }, ], - ideKey: 'PLAYGROUNDCLI', + ideKey: 'PHPWASMCLI', }; describe('valid configurations', () => { @@ -120,7 +120,7 @@ describe('updatePhpStormConfig', () => { - + @@ -146,7 +146,7 @@ describe('updatePhpStormConfig', () => { - + @@ -179,7 +179,7 @@ describe('updatePhpStormConfig', () => { - + @@ -205,6 +205,37 @@ describe('updatePhpStormConfig', () => { expect(configMatches.length).toBe(1); }); + it('should handle no path mapping', () => { + const options: PhpStormConfigOptions = { + name: 'Test Server', + host: 'localhost', + port: 8080, + projectDir: process.cwd(), + ideKey: 'PHPWASMCLI', + }; + + const xml = + '\n\n'; + const result = updatePhpStormConfig(xml, options); + + const expected = ` + + + + + + + + + + + + +`; + + expectXMLEquals(result, expected); + }); + it('should handle multiple path mappings', () => { const options: PhpStormConfigOptions = { ...defaultOptions, @@ -242,7 +273,7 @@ describe('updatePhpStormConfig', () => { - + @@ -283,7 +314,7 @@ describe('updatePhpStormConfig', () => { - + @@ -324,7 +355,7 @@ describe('updatePhpStormConfig', () => { - + @@ -354,7 +385,7 @@ describe('updatePhpStormConfig', () => { - + @@ -376,7 +407,7 @@ describe('updatePhpStormConfig', () => { - + @@ -448,7 +479,7 @@ describe('updatePhpStormConfig', () => { - + @@ -514,12 +545,11 @@ describe('updatePhpStormConfig', () => { - - + @@ -552,7 +582,7 @@ describe('updatePhpStormConfig', () => { - + @@ -585,7 +615,7 @@ describe('updatePhpStormConfig', () => { - + @@ -616,7 +646,7 @@ describe('updatePhpStormConfig', () => { - + @@ -652,7 +682,7 @@ describe('updatePhpStormConfig', () => { - + @@ -693,7 +723,7 @@ describe('updatePhpStormConfig', () => { - + @@ -722,7 +752,7 @@ describe('updatePhpStormConfig', () => { - + @@ -855,6 +885,29 @@ describe('updateVSCodeConfig', () => { expect(matches?.length).toBe(1); }); + it('should handle no path mapping', () => { + const options: VSCodeConfigOptions = { + name: 'Test Configuration', + workspaceDir: process.cwd(), + }; + + const json = '{\n "configurations": []\n}'; + const result = updateVSCodeConfig(json, options); + + const expected = `{ + "configurations": [ + { + "name": "Test Configuration", + "type": "php", + "request": "launch", + "port": 9003, + } + ] +}`; + + expectJSONEquals(result, expected); + }); + it('should handle multiple path mappings', () => { const options: VSCodeConfigOptions = { ...defaultOptions, @@ -1120,7 +1173,6 @@ describe('updateVSCodeConfig', () => { "type": "php", "request": "launch", "port": 9003, - "pathMappings": {} } ] }`; diff --git a/packages/php-wasm/cli-util/tsconfig.json b/packages/php-wasm/cli-util/tsconfig.json new file mode 100644 index 0000000000..3dd0ac8fdc --- /dev/null +++ b/packages/php-wasm/cli-util/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "types": ["vitest"] + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/php-wasm/cli-util/tsconfig.lib.json b/packages/php-wasm/cli-util/tsconfig.lib.json new file mode 100644 index 0000000000..d54256fda2 --- /dev/null +++ b/packages/php-wasm/cli-util/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["vite.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] +} diff --git a/packages/php-wasm/cli-util/tsconfig.spec.json b/packages/php-wasm/cli-util/tsconfig.spec.json new file mode 100644 index 0000000000..eb23daacbc --- /dev/null +++ b/packages/php-wasm/cli-util/tsconfig.spec.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"] + }, + "include": [ + "vite.config.ts", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.test.tsx", + "src/**/*.spec.tsx", + "src/**/*.test.js", + "src/**/*.spec.js", + "src/**/*.test.jsx", + "src/**/*.spec.jsx", + "src/**/*.d.ts" + ] +} diff --git a/packages/php-wasm/cli-util/vite.config.ts b/packages/php-wasm/cli-util/vite.config.ts new file mode 100644 index 0000000000..d0d8fbb3cc --- /dev/null +++ b/packages/php-wasm/cli-util/vite.config.ts @@ -0,0 +1,54 @@ +/// +import { defineConfig } from 'vite'; + +import dts from 'vite-plugin-dts'; +import { join } from 'path'; + +import viteTsConfigPaths from 'vite-tsconfig-paths'; +// eslint-disable-next-line @nx/enforce-module-boundaries +import { getExternalModules } from '../../vite-extensions/vite-external-modules'; +// eslint-disable-next-line @nx/enforce-module-boundaries +import viteGlobalExtensions from '../../vite-extensions/vite-global-extensions'; + +export default defineConfig({ + cacheDir: '../../../node_modules/.vite/php-wasm-cli-util', + + plugins: [ + dts({ + entryRoot: 'src', + tsconfigPath: join(__dirname, 'tsconfig.lib.json'), + pathsToAliases: false, + }), + + viteTsConfigPaths({ + root: '../../../', + }), + + ...viteGlobalExtensions, + ], + + build: { + lib: { + // Could also be a dictionary or array of multiple entry points. + entry: 'src/index.ts', + name: 'php-wasm-cli-util', + fileName: 'index', + formats: ['es', 'cjs'], + }, + sourcemap: true, + rollupOptions: { + // External packages that should not be bundled into your library. + external: getExternalModules(), + }, + }, + + test: { + globals: true, + cache: { + dir: '../../../node_modules/.vitest', + }, + environment: 'node', + include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], + reporters: ['default'], + }, +}); diff --git a/packages/php-wasm/cli/src/main.ts b/packages/php-wasm/cli/src/main.ts index 06f509627c..2431ae8808 100644 --- a/packages/php-wasm/cli/src/main.ts +++ b/packages/php-wasm/cli/src/main.ts @@ -9,12 +9,13 @@ import { LatestSupportedPHPVersion, SupportedPHPVersionsList, } from '@php-wasm/universal'; +/* eslint-disable no-console */ import type { SupportedPHPVersion } from '@php-wasm/universal'; - import { FileLockManagerForNode } from '@php-wasm/node'; import { PHP } from '@php-wasm/universal'; import { loadNodeRuntime, useHostFilesystem } from '@php-wasm/node'; import { startBridge } from '@php-wasm/xdebug-bridge'; +import { addXdebugIDEConfig, clearXdebugIDEConfig } from '@php-wasm/cli-util'; import path from 'path'; let args = process.argv.slice(2); @@ -22,6 +23,15 @@ if (!args.length) { args = ['--help']; } +const bold = (text: string) => + process.stdout.isTTY ? '\x1b[1m' + text + '\x1b[0m' : text; + +const italic = (text: string) => + process.stdout.isTTY ? `\x1b[3m${text}\x1b[0m` : text; + +const highlight = (text: string) => + process.stdout.isTTY ? `\x1b[33m${text}\x1b[0m` : text; + const baseUrl = (import.meta || {}).url; // Write the ca-bundle.crt file to disk so that PHP can find it. @@ -51,6 +61,23 @@ async function run() { args = args.filter((arg) => arg !== '--experimental-devtools'); } + const experimentalUnsafeIDEIntegrationOptions = + args + .filter((arg) => + arg.startsWith('--experimental-unsafe-ide-integration') + ) + .map((arg) => { + const value = arg.split('=')[1]; + if (value === undefined) return ['vscode', 'phpstorm']; + if (value.includes(',')) return value.split(','); + return [value]; + })[0] ?? false; + if (experimentalUnsafeIDEIntegrationOptions) { + args = args.filter( + (arg) => !arg.startsWith('--experimental-unsafe-ide-integration') + ); + } + // npm scripts set the TMPDIR env variable // PHP accepts a TMPDIR env variable and expects it to // be a writable directory within the PHP filesystem. @@ -105,7 +132,90 @@ ${process.argv[0]} ${process.execArgv.join(' ')} ${process.argv[1]} useHostFilesystem(php); - if (hasDevtoolsOption && hasXdebugOption) { + // If xdebug, and experimental IDE are enabled, + // add the new IDE config. + if (hasXdebugOption && experimentalUnsafeIDEIntegrationOptions) { + try { + const IDEConfigName = 'PHP.wasm CLI - Listen for Xdebug'; + const ides = experimentalUnsafeIDEIntegrationOptions; + + // NOTE: Both the 'clear' and 'add' operations can throw errors. + await clearXdebugIDEConfig(IDEConfigName, process.cwd()); + + const modifiedConfig = await addXdebugIDEConfig({ + name: IDEConfigName, + host: 'example.com', + port: 443, + ides: ides, + cwd: process.cwd(), + }); + + // Display IDE-specific instructions + const hasVSCode = ides.includes('vscode'); + const hasPhpStorm = ides.includes('phpstorm'); + const configFiles = Object.values(modifiedConfig); + + console.log(''); + + if (configFiles.length > 0) { + console.log(bold(`Xdebug configured successfully`)); + console.log( + highlight(`Updated IDE config: `) + configFiles.join(' ') + ); + } else { + console.log(bold(`Xdebug configuration failed.`)); + console.log( + 'No IDE-specific project settings directory was found in the current working directory.' + ); + } + + console.log(''); + + if (hasVSCode && modifiedConfig['vscode']) { + console.log(bold('VS Code / Cursor instructions:')); + console.log( + ' 1. Ensure you have installed an IDE extension for PHP Debugging' + ); + console.log( + ` (The ${bold('PHP Debug')} extension by ${bold( + 'Xdebug' + )} has been a solid option)` + ); + console.log( + ' 2. Open the Run and Debug panel on the left sidebar' + ); + console.log( + ` 3. Select "${italic(IDEConfigName)}" from the dropdown` + ); + console.log(' 3. Click "start debugging"'); + console.log(' 5. Set a breakpoint.'); + console.log(' 6. Run your command with PHP.wasm CLI.'); + if (hasPhpStorm) { + console.log(''); + } + } + + if (hasPhpStorm && modifiedConfig['phpstorm']) { + console.log(bold('PhpStorm instructions:')); + console.log( + ` 1. Choose "${italic( + IDEConfigName + )}" debug configuration in the toolbar` + ); + console.log(' 2. Click the debug button (bug icon)`'); + console.log(' 3. Set a breakpoint.'); + console.log(' 4. Run your command with PHP.wasm CLI.'); + } + + console.log(''); + } catch (error) { + throw new Error('Could not configure Xdebug', { + cause: error, + }); + } + } + + if (hasXdebugOption && hasDevtoolsOption) { const bridge = await startBridge({ breakOnFirstLine: true }); bridge.start(); diff --git a/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts b/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts index 5aecb031fc..89cdfd13b3 100644 --- a/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts +++ b/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts @@ -21,11 +21,7 @@ import { jspi } from 'wasm-feature-detect'; import { MessageChannel, type MessagePort, parentPort } from 'worker_threads'; import { mountResources } from '../mounts'; import { logger } from '@php-wasm/logger'; - -export interface Mount { - hostPath: string; - vfsPath: string; -} +import type { Mount } from '@php-wasm/cli-util'; export type WorkerBootOptions = { phpVersion: SupportedPHPVersion; @@ -192,7 +188,7 @@ export class PlaygroundCliBlueprintV1Worker extends PHPWorker { ? new File( [sqliteIntegrationPluginZip], 'sqlite-integration-plugin.zip' - ) + ) : undefined, sapiName: 'cli', createFiles: { diff --git a/packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts b/packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts index 82a1a12c76..0f84f02e9a 100644 --- a/packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts +++ b/packages/playground/cli/src/blueprints-v2/worker-thread-v2.ts @@ -32,7 +32,6 @@ import { existsSync } from 'fs'; import path from 'path'; import { rootCertificates } from 'tls'; import { MessageChannel, type MessagePort, parentPort } from 'worker_threads'; -import type { Mount } from '../mounts'; import { jspi } from 'wasm-feature-detect'; import { type RunCLIArgs } from '../run-cli'; import type { @@ -40,6 +39,7 @@ import type { PHPInstanceCreatedHook, } from '@wp-playground/wordpress'; import { shouldRenderProgress } from '../utils/progress'; +import type { Mount } from '@php-wasm/cli-util'; async function mountResources(php: PHP, mounts: Mount[]) { for (const mount of mounts) { diff --git a/packages/playground/cli/src/mounts.ts b/packages/playground/cli/src/mounts.ts index 80adda0707..008df20ea2 100644 --- a/packages/playground/cli/src/mounts.ts +++ b/packages/playground/cli/src/mounts.ts @@ -3,11 +3,7 @@ import type { PHP } from '@php-wasm/universal'; import fs, { existsSync } from 'fs'; import path, { basename, join } from 'path'; import type { RunCLIArgs } from './run-cli'; - -export interface Mount { - hostPath: string; - vfsPath: string; -} +import type { Mount } from '@php-wasm/cli-util'; /** * Parse an array of mount argument strings where the host path and VFS path @@ -146,11 +142,11 @@ export function expandAutoMounts(args: RunCLIArgs): RunCLIArgs { ? { step: 'activateTheme', themeDirectoryName: themeName, - } + } : { step: 'activateTheme', themeFolderName: themeName, - } + } ); } else if (containsWpContentDirectories(path)) { /** diff --git a/packages/playground/cli/src/run-cli.ts b/packages/playground/cli/src/run-cli.ts index f1ffbb914b..d77f6cf7aa 100644 --- a/packages/playground/cli/src/run-cli.ts +++ b/packages/playground/cli/src/run-cli.ts @@ -28,10 +28,7 @@ import { parseMountWithDelimiterArguments, } from './mounts'; import { startServer } from './start-server'; -import type { - Mount, - PlaygroundCliBlueprintV1Worker, -} from './blueprints-v1/worker-thread-v1'; +import type { PlaygroundCliBlueprintV1Worker } from './blueprints-v1/worker-thread-v1'; import type { PlaygroundCliBlueprintV2Worker } from './blueprints-v2/worker-thread-v2'; import { FileLockManagerForNode } from '@php-wasm/node'; import { LoadBalancer } from './load-balancer'; @@ -54,11 +51,12 @@ import { } from './temp-dir'; import { type WordPressInstallMode } from '@wp-playground/wordpress'; import { + type Mount, addXdebugIDEConfig, clearXdebugIDEConfig, - createPlaygroundCliTempDirSymlink, - removePlaygroundCliTempDirSymlink, -} from './xdebug-path-mappings'; + createTempDirSymlink, + removeTempDirSymlink, +} from '@php-wasm/cli-util'; // Inlined worker URLs for static analysis by downstream bundlers // These are replaced at build time by the Vite plugin in vite.config.ts @@ -695,13 +693,13 @@ export async function runCLI(args: RunCLIArgs): Promise { const symlinkName = '.playground-xdebug-root'; const symlinkPath = path.join(process.cwd(), symlinkName); - await removePlaygroundCliTempDirSymlink(symlinkPath); + await removeTempDirSymlink(symlinkPath); // Then, if xdebug, and experimental IDE are enabled, // recreate the symlink pointing to the temporary // directory and add the new IDE config. if (args.xdebug && args.experimentalUnsafeIdeIntegration) { - await createPlaygroundCliTempDirSymlink( + await createTempDirSymlink( nativeDir.path, symlinkPath, process.platform @@ -738,25 +736,35 @@ export async function runCLI(args: RunCLIArgs): Promise { const ides = args.experimentalUnsafeIdeIntegration; const hasVSCode = ides.includes('vscode'); const hasPhpStorm = ides.includes('phpstorm'); + const configFiles = Object.values(modifiedConfig); console.log(''); - console.log(bold(`Xdebug configured successfully`)); - console.log( - highlight(`Updated IDE config: `) + - modifiedConfig.join(' ') - ); - console.log( - highlight('Playground source root: ') + - `.playground-xdebug-root` + - italic( - dim( - ` – you can set breakpoints and preview Playground's VFS structure in there.` + + if (configFiles.length > 0) { + console.log(bold(`Xdebug configured successfully`)); + console.log( + highlight(`Updated IDE config: `) + + configFiles.join(' ') + ); + console.log( + highlight('Playground source root: ') + + `.playground-xdebug-root` + + italic( + dim( + ` – you can set breakpoints and preview Playground's VFS structure in there.` + ) ) - ) - ); + ); + } else { + console.log(bold(`Xdebug configuration failed.`)); + console.log( + 'No IDE-specific project settings directory was found in the current working directory.' + ); + } + console.log(''); - if (hasVSCode) { + if (hasVSCode && modifiedConfig['vscode']) { console.log(bold('VS Code / Cursor instructions:')); console.log( ' 1. Ensure you have installed an IDE extension for PHP Debugging' @@ -786,7 +794,7 @@ export async function runCLI(args: RunCLIArgs): Promise { } } - if (hasPhpStorm) { + if (hasPhpStorm && modifiedConfig['phpstorm']) { console.log(bold('PhpStorm instructions:')); console.log( ` 1. Choose "${italic( diff --git a/tsconfig.base.json b/tsconfig.base.json index 0a4f8d2954..cf1f2680d2 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -18,6 +18,7 @@ "baseUrl": ".", "paths": { "@php-wasm/cli": ["packages/php-wasm/cli/src/main.ts"], + "@php-wasm/cli-util": ["packages/php-wasm/cli-util/src/index.ts"], "@php-wasm/fs-journal": [ "packages/php-wasm/fs-journal/src/index.ts" ],