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..614cae84da
--- /dev/null
+++ b/packages/php-wasm/cli-util/package.json
@@ -0,0 +1,46 @@
+{
+ "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",
+ "contributors": [
+ {
+ "name": "Adam Zielinski",
+ "email": "adam@adamziel.com",
+ "url": "https://github.com/adamziel"
+ }
+ ],
+ "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..b8321818be 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,9 +465,9 @@ export async function addXdebugIDEConfig({
port,
cwd,
mounts,
- ideKey = 'PLAYGROUNDCLI',
+ ideKey = 'PHPWASMCLI',
}: IDEConfig) {
- const mappings = filterLocalMounts(cwd, mounts);
+ const mappings = mounts ? filterLocalMounts(cwd, mounts) : [];
const modifiedConfig: string[] = [];
// PHPstorm
@@ -500,9 +504,8 @@ export async function addXdebugIDEConfig({
ideKey,
});
fs.writeFileSync(phpStormConfigFilePath, updatedXml);
+ modifiedConfig.push(phpStormRelativeConfigFilePath);
}
-
- modifiedConfig.push(phpStormRelativeConfigFilePath);
}
// VSCode
@@ -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..2506933122 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,89 @@ ${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');
+
+ console.log('');
+
+ if (modifiedConfig.length > 0) {
+ console.log(bold(`Xdebug configured successfully`));
+ console.log(
+ highlight(`Updated IDE config: `) + modifiedConfig.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) {
+ 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) {
+ 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..5da5240322 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
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"
],