mirror of
https://github.com/anomalyco/opencode.git
synced 2026-09-24 01:27:36 +00:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bed540c5cb | ||
|
|
cf0af1dec8 | ||
|
|
6f115f7e89 | ||
|
|
ffe2284332 | ||
|
|
6345548b5f | ||
|
|
17a04f1f71 | ||
|
|
094a08b09c | ||
|
|
6775d13f59 |
@@ -192,7 +192,7 @@
|
||||
"zod": "catalog:",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"effect": "4.0.0-rc.112",
|
||||
"effect": "4.0.0-rc.115",
|
||||
"solid-js": ">=1.9.0",
|
||||
},
|
||||
"optionalPeers": [
|
||||
@@ -367,7 +367,7 @@
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"fuzzysort": "3.1.0",
|
||||
"gitlab-ai-provider": "6.16.0",
|
||||
"gitlab-ai-provider": "6.12.1",
|
||||
"google-auth-library": "10.5.0",
|
||||
"gray-matter": "4.0.3",
|
||||
"htmlparser2": "8.0.2",
|
||||
@@ -403,6 +403,7 @@
|
||||
"@types/node": "catalog:",
|
||||
"@types/which": "3.0.4",
|
||||
"drizzle-kit": "catalog:",
|
||||
"fast-check": "catalog:",
|
||||
},
|
||||
},
|
||||
"packages/desktop": {
|
||||
@@ -511,7 +512,7 @@
|
||||
"name": "@opencode/http-recorder",
|
||||
"version": "2.0.14",
|
||||
"dependencies": {
|
||||
"@effect/platform-node-shared": "4.0.0-rc.112",
|
||||
"@effect/platform-node-shared": "4.0.0-rc.115",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@effect/platform-node": "catalog:",
|
||||
@@ -1099,10 +1100,10 @@
|
||||
"catalog": {
|
||||
"@cloudflare/workers-types": "4.20251008.0",
|
||||
"@corvu/drawer": "0.2.4",
|
||||
"@effect/opentelemetry": "4.0.0-rc.112",
|
||||
"@effect/platform-node": "4.0.0-rc.112",
|
||||
"@effect/platform-node-shared": "4.0.0-rc.112",
|
||||
"@effect/sql-sqlite-bun": "4.0.0-rc.112",
|
||||
"@effect/opentelemetry": "4.0.0-rc.115",
|
||||
"@effect/platform-node": "4.0.0-rc.115",
|
||||
"@effect/platform-node-shared": "4.0.0-rc.115",
|
||||
"@effect/sql-sqlite-bun": "4.0.0-rc.115",
|
||||
"@hono/standard-validator": "0.2.0",
|
||||
"@hono/zod-validator": "0.4.2",
|
||||
"@kobalte/core": "0.13.13",
|
||||
@@ -1142,7 +1143,8 @@
|
||||
"dompurify": "3.4.14",
|
||||
"drizzle-kit": "1.0.0-rc.5-ab785fc",
|
||||
"drizzle-orm": "1.0.0-rc.5-169397b",
|
||||
"effect": "4.0.0-rc.112",
|
||||
"effect": "4.0.0-rc.115",
|
||||
"fast-check": "4.9.0",
|
||||
"fuzzysort": "3.1.0",
|
||||
"get-east-asian-width": "1.6.0",
|
||||
"hono": "4.10.7",
|
||||
@@ -1674,13 +1676,13 @@
|
||||
|
||||
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.12.0", "", {}, "sha512-mlUE+rZ8CatQekLhnaiN91Iemdd+e2gFKooGlnRB3oPTL3VghLfX24dx7HrzMNeC1JrIB/0kpsfyty3f5HNfxQ=="],
|
||||
|
||||
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.112", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.112" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-OTRv1DxTHUmnakgJ6XVM8wVgF1KgZH4UXnOemwSLUwUjXO+RCikzF8oR/rlVmOGq81KtQzj1URM4M4nchlQOuQ=="],
|
||||
"@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.115", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.115" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-ITOqqf/Z0mrs6XhuV8wb4YYFt0sdMhXZGPtytr+YG87YG6mFdYkc8IaJj8cGQFKRkGota/2CN+zjBKhQVI64OQ=="],
|
||||
|
||||
"@effect/platform-node": ["@effect/platform-node@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112", "mime": "^4.1.0", "undici": "^8.10.0" }, "peerDependencies": { "effect": "^4.0.0-rc.112", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/BMAcdNGQQskLmI0Zoa95KfTZkr9HV9N4NSxaSrusG6GeW6Ulp9KvZ+Rlaiw8lnOt43CXjFLdfll5/k5rxL4hQ=="],
|
||||
"@effect/platform-node": ["@effect/platform-node@4.0.0-rc.115", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.115", "undici": "^8.10.2" }, "peerDependencies": { "effect": "^4.0.0-rc.115", "redis": ">=5.0.0 <7.0.0" } }, "sha512-mW03Wjq2FiTL5oi9yOkaKpCyUNBaduKgTk7qMHNELvC21Jq2qOAfdsfH+p+s2zmpB9w2RSa+ApODv4WjO9wQfw=="],
|
||||
|
||||
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="],
|
||||
"@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.115", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.115" } }, "sha512-rcBwhDIfb82akJoTv7Vwh8K5x9vC/XfuePS7JjOr+z+dORXzsmKqI1BUQF27ARCN9fTAbDh7I6YvBlWhLjnqNg=="],
|
||||
|
||||
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-rc.112", "", { "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-EqR8pWZo3VzedRvP6qo5HcfqNmFvSa+sQLWQl3oBMx2KY1FCc8NYjep79wYjNkW0qABnffrPUXCMTOncd1A+5g=="],
|
||||
"@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-rc.115", "", { "peerDependencies": { "effect": "^4.0.0-rc.115" } }, "sha512-CypwmCPAUSOOhopcnSI9ocgpKHfpgOdERpei3GuXZm5cCGP31pk2NUETqNaYhonhr2bWd+6Rc8atctnEbIYKYQ=="],
|
||||
|
||||
"@electron-internal/extract-zip": ["@electron-internal/extract-zip@1.0.5", "", {}, "sha512-+bqFCP98pLI0Tt0XQo1TmlXtwjWchISndDOxCkEcIuUgXWpBnLyRI+2DU+mesvnMMX6L1XDqYNA0lXNDHd/yiA=="],
|
||||
|
||||
@@ -2014,18 +2016,6 @@
|
||||
|
||||
"@motionone/utils": ["@motionone/utils@10.18.0", "", { "dependencies": { "@motionone/types": "^10.17.1", "hey-listen": "^1.0.8", "tslib": "^2.3.1" } }, "sha512-3XVF7sgyTSI2KWvTf6uLlBJ5iAgRgmvp3bpuOiQJvInd4nZ19ET8lX5unn30SlmRH7hXbBbH+Gxd0m0klJ3Xtw=="],
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="],
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="],
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4", "", { "os": "linux", "cpu": "arm" }, "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw=="],
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw=="],
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ=="],
|
||||
|
||||
"@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="],
|
||||
|
||||
"@napi-rs/lzma-linux-x64-gnu": ["@napi-rs/lzma-linux-x64-gnu@1.5.1", "", { "os": "linux", "cpu": "x64" }, "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ=="],
|
||||
|
||||
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.2.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" } }, "sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q=="],
|
||||
@@ -3878,7 +3868,7 @@
|
||||
|
||||
"editorconfig": ["editorconfig@1.0.7", "", { "dependencies": { "@one-ini/wasm": "0.1.1", "commander": "^10.0.0", "minimatch": "^9.0.1", "semver": "^7.5.3" }, "bin": { "editorconfig": "bin/editorconfig" } }, "sha512-e0GOtq/aTQhVdNyDU9e02+wz9oDDM+SIOQxWME2QRjzRX5yyLAuHDE+0aE8vHb9XRC8XD37eO2u57+F09JqFhw=="],
|
||||
|
||||
"effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="],
|
||||
"effect": ["effect@4.0.0-rc.115", "", {}, "sha512-ogYulZ5ffeOzrJqQrG0XOkDO5lKn2s9KNHhoxJy/6wKUkF0i12dlVXWA9TgsgQ+zV/JzizyG0+XMPepZEQX6vw=="],
|
||||
|
||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||
|
||||
@@ -4128,7 +4118,7 @@
|
||||
|
||||
"github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="],
|
||||
|
||||
"gitlab-ai-provider": ["gitlab-ai-provider@6.16.0", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-HMC3sKgWYaYSsgm86Cnq2e6laHlYkhiFQ6rFD5qsVghv9//6h4Ofr7j5R2KjQx9Hl8EBercPsmzjoEjEN7dX5Q=="],
|
||||
"gitlab-ai-provider": ["gitlab-ai-provider@6.12.1", "", { "dependencies": { "@anthropic-ai/sdk": "^0.71.0", "@anycable/core": "^0.9.2", "graphql-request": "^6.1.0", "isomorphic-ws": "^5.0.0", "openai": "^6.16.0", "socket.io-client": "^4.8.1", "vscode-jsonrpc": "^8.2.1", "zod": "^3.25.76" }, "peerDependencies": { "@ai-sdk/provider": ">=3.0.0", "@ai-sdk/provider-utils": ">=4.0.0" } }, "sha512-Qn5iHqvjG8yktI5MWaUgdRR94l7O4WtYW0CAbhsCh1Tj0Fei/DeprOYPVyf4Nht1Ix6U2PXSYM32QOHI6Z2TDw=="],
|
||||
|
||||
"glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="],
|
||||
|
||||
@@ -4714,7 +4704,7 @@
|
||||
|
||||
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
||||
|
||||
"mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="],
|
||||
"mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
|
||||
|
||||
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
||||
|
||||
@@ -4762,10 +4752,6 @@
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"msgpackr": ["msgpackr@2.0.5", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-cef05H/dSYpLpqp3sj/qyZh5vhUYCalnaLO7j1yOmpsR0y/XwLVtK7r5gn+U/F7CTEfMowcGhlUQJDLcLf7jcA=="],
|
||||
|
||||
"msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="],
|
||||
|
||||
"muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="],
|
||||
|
||||
"mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="],
|
||||
@@ -4808,8 +4794,6 @@
|
||||
|
||||
"node-gyp-build": ["node-gyp-build@4.8.4", "", { "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", "node-gyp-build-test": "build-test.js" } }, "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ=="],
|
||||
|
||||
"node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="],
|
||||
|
||||
"node-html-parser": ["node-html-parser@7.1.0", "", { "dependencies": { "css-select": "^5.1.0", "he": "1.2.0" } }, "sha512-iJo8b2uYGT40Y8BTyy5ufL6IVbN8rbm/1QK2xffXU/1a/v3AAa0d1YAoqBNYqaS4R/HajkWIpIfdE6KcyFh1AQ=="],
|
||||
|
||||
"node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="],
|
||||
@@ -5606,7 +5590,7 @@
|
||||
|
||||
"uncrypto": ["uncrypto@0.1.3", "", {}, "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q=="],
|
||||
|
||||
"undici": ["undici@8.10.0", "", {}, "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ=="],
|
||||
"undici": ["undici@8.10.2", "", {}, "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ=="],
|
||||
|
||||
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
||||
|
||||
@@ -6060,8 +6044,6 @@
|
||||
|
||||
"@bufbuild/protoplugin/typescript": ["typescript@5.4.5", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ=="],
|
||||
|
||||
"@cloudflare/kv-asset-handler/mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="],
|
||||
|
||||
"@cloudflare/vite-plugin/vite": ["vite@7.3.6", "", { "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rollup": "^4.43.0", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", "less": "^4.0.0", "lightningcss": "^1.21.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "jiti", "less", "lightningcss", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg=="],
|
||||
|
||||
"@cloudflare/vite-plugin/ws": ["ws@8.18.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="],
|
||||
@@ -6662,6 +6644,8 @@
|
||||
|
||||
"tw-to-css/tailwindcss": ["tailwindcss@3.3.2", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.2.12", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", "postcss": "^8.4.23", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w=="],
|
||||
|
||||
"unifont/undici": ["undici@8.10.0", "", {}, "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ=="],
|
||||
|
||||
"unplugin/acorn": ["acorn@8.18.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ=="],
|
||||
|
||||
"unused-filename/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"nodeModules": {
|
||||
"x86_64-linux": "sha256-DVimx64BQEkFaYZkW56E5eEfkGxuW5j/9C0wCImBFl4=",
|
||||
"aarch64-linux": "sha256-MhMl/ZkvcPXE31OvysutI6nKIJ6XtUa3c71+B4hnaQc=",
|
||||
"aarch64-darwin": "sha256-+wMPYLBnw2zTZj0if8EPwWC9O3tVqSgnhYNfQq8UZ8Q=",
|
||||
"x86_64-darwin": "sha256-l6LxVSXDbqVoXMVcGZAzRER0bxP6wDU4dfRDolx0JGM="
|
||||
"x86_64-linux": "sha256-WBGj4wU5PQs+0zbDbScFhJs0GL8qWnswIsJb/Kee5Qc=",
|
||||
"aarch64-linux": "sha256-Z8hkyNMdqCpuv24q50QhO2RECINvENjBhLDY5FKcnFc=",
|
||||
"aarch64-darwin": "sha256-HZHb9HcXMOc7bKR7eADQSyfWxX37GAcoRi/EMSpRiP4=",
|
||||
"x86_64-darwin": "sha256-CcWCOAcW4t9ADs48fMhumSbDcQWdk91LpkG6fe/gWlk="
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -42,10 +42,10 @@
|
||||
"packages/stats/*"
|
||||
],
|
||||
"catalog": {
|
||||
"@effect/opentelemetry": "4.0.0-rc.112",
|
||||
"@effect/platform-node": "4.0.0-rc.112",
|
||||
"@effect/platform-node-shared": "4.0.0-rc.112",
|
||||
"@effect/sql-sqlite-bun": "4.0.0-rc.112",
|
||||
"@effect/opentelemetry": "4.0.0-rc.115",
|
||||
"@effect/platform-node": "4.0.0-rc.115",
|
||||
"@effect/platform-node-shared": "4.0.0-rc.115",
|
||||
"@effect/sql-sqlite-bun": "4.0.0-rc.115",
|
||||
"@npmcli/arborist": "9.4.0",
|
||||
"@types/bun": "1.4.0",
|
||||
"@types/cross-spawn": "6.0.6",
|
||||
@@ -79,7 +79,8 @@
|
||||
"dompurify": "3.4.14",
|
||||
"drizzle-kit": "1.0.0-rc.5-ab785fc",
|
||||
"drizzle-orm": "1.0.0-rc.5-169397b",
|
||||
"effect": "4.0.0-rc.112",
|
||||
"effect": "4.0.0-rc.115",
|
||||
"fast-check": "4.9.0",
|
||||
"ai": "6.0.168",
|
||||
"cross-spawn": "7.0.6",
|
||||
"hono": "4.10.7",
|
||||
|
||||
@@ -26,7 +26,7 @@ import { OpenAI } from "@opencode/ai/providers"
|
||||
* hover imports and local values to see how the public API is typed.
|
||||
*/
|
||||
|
||||
const apiKey = Config.redacted("OPENAI_API_KEY")
|
||||
const apiKey = Config.Redacted("OPENAI_API_KEY")
|
||||
|
||||
// 1. Configure a provider. The configured facade records provider identity,
|
||||
// deployment options, authentication, and defaults. Per-modality selectors pick
|
||||
|
||||
@@ -278,7 +278,7 @@ const readEnvFile = Effect.fn("RecordingEnv.readFile")(function* () {
|
||||
})
|
||||
|
||||
const readConfigString = (provider: ConfigProvider.ConfigProvider, name: string) =>
|
||||
Config.string(name)
|
||||
Config.String(name)
|
||||
.parse(provider)
|
||||
.pipe(
|
||||
Effect.match({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Effect, Option, Schema } from "effect"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { Tool } from "@opencode/schema/tool"
|
||||
import { Route } from "../route/client.js"
|
||||
import { Auth } from "../route/auth.js"
|
||||
@@ -76,44 +76,6 @@ const OpenAIChatAssistantToolCall = Schema.Struct({
|
||||
})
|
||||
type OpenAIChatAssistantToolCall = Schema.Schema.Type<typeof OpenAIChatAssistantToolCall>
|
||||
|
||||
// `reasoning_details` carries two dialects. OpenRouter's `reasoning.*` entries
|
||||
// must be replayed unmodified (`index` included), so they keep every field they
|
||||
// arrived with. Kimi's OpenAI-compatible surface streams preserved thinking as
|
||||
// bare `summary` / `encrypted` entries keyed by a stream-only `index`; Kimi does
|
||||
// not document this publicly, so the handling follows Kimi Code (Kimi's own
|
||||
// client): merge summary deltas by `index`, replay without `index`, and always
|
||||
// send `reasoning_content` alongside. Anything else is dropped at the boundary.
|
||||
const OpenRouterDetailFields = {
|
||||
id: Schema.optional(Schema.NullOr(Schema.String)),
|
||||
format: Schema.optional(Schema.String),
|
||||
index: Schema.optional(Schema.Number),
|
||||
signature: Schema.optional(Schema.NullOr(Schema.String)),
|
||||
}
|
||||
const ReasoningDetail = Schema.Union([
|
||||
Schema.StructWithRest(
|
||||
Schema.Struct({ type: Schema.Literal("reasoning.text"), text: Schema.optional(Schema.String), ...OpenRouterDetailFields }),
|
||||
[Schema.Record(Schema.String, Schema.Unknown)],
|
||||
),
|
||||
Schema.StructWithRest(
|
||||
Schema.Struct({
|
||||
type: Schema.Literal("reasoning.summary"),
|
||||
summary: Schema.optional(Schema.String),
|
||||
...OpenRouterDetailFields,
|
||||
}),
|
||||
[Schema.Record(Schema.String, Schema.Unknown)],
|
||||
),
|
||||
Schema.StructWithRest(
|
||||
Schema.Struct({ type: Schema.Literal("reasoning.encrypted"), data: Schema.String, ...OpenRouterDetailFields }),
|
||||
[Schema.Record(Schema.String, Schema.Unknown)],
|
||||
),
|
||||
Schema.Struct({ type: Schema.Literal("summary"), summary: Schema.String, index: Schema.optional(Schema.Number) }),
|
||||
Schema.Struct({ type: Schema.Literal("encrypted"), encrypted: Schema.String, index: Schema.optional(Schema.Number) }),
|
||||
])
|
||||
type ReasoningDetail = Schema.Schema.Type<typeof ReasoningDetail>
|
||||
const decodeReasoningDetail = Schema.decodeUnknownOption(ReasoningDetail)
|
||||
const knownReasoningDetails = (details: ReadonlyArray<unknown>) =>
|
||||
details.flatMap((detail) => Option.toArray(decodeReasoningDetail(detail)))
|
||||
|
||||
// Intentionally omit Gemini's provider-specific `extra_content.google.thought_signature`
|
||||
// extension until direct Google OpenAI-compatible routing is supported here:
|
||||
// https://github.com/vercel/ai/issues/11590
|
||||
@@ -303,9 +265,7 @@ export interface ParserState {
|
||||
readonly finishReason?: FinishReasonDetails
|
||||
readonly lifecycle: Lifecycle.State
|
||||
readonly reasoningField?: string
|
||||
/** A scalar reasoning field (`reasoning_content`, ...) has carried text in this stream. */
|
||||
readonly reasoningTextObserved: boolean
|
||||
readonly reasoningDetails: Array<ReasoningDetail>
|
||||
readonly reasoningDetails: Array<unknown>
|
||||
readonly reasoningDetailsObserved: boolean
|
||||
readonly reasoningEmitted: boolean
|
||||
readonly latestToolIndex?: number
|
||||
@@ -381,21 +341,10 @@ const reasoningDetails = (parts: ReadonlyArray<ReasoningPart>, native: unknown,
|
||||
return Array.isArray(details) ? details : []
|
||||
})
|
||||
if (parts.some((part) => Array.isArray(part.providerMetadata?.[providerMetadataKey]?.reasoningDetails)))
|
||||
return knownReasoningDetails(observed).map(lowerReasoningDetail)
|
||||
if (isRecord(native) && Array.isArray(native.reasoning_details))
|
||||
return knownReasoningDetails(native.reasoning_details).map(lowerReasoningDetail)
|
||||
return observed
|
||||
if (isRecord(native) && Array.isArray(native.reasoning_details)) return native.reasoning_details
|
||||
}
|
||||
|
||||
// Kimi rejects its stream-only `index` on requests
|
||||
// ("the reasoning_details ... must not contain streaming index").
|
||||
const lowerReasoningDetail = (detail: ReasoningDetail) => {
|
||||
if (detail.type === "summary") return { type: detail.type, summary: detail.summary }
|
||||
if (detail.type === "encrypted") return { type: detail.type, encrypted: detail.encrypted }
|
||||
return detail
|
||||
}
|
||||
|
||||
const isKimiDetail = (detail: { readonly type: string }) => detail.type === "summary" || detail.type === "encrypted"
|
||||
|
||||
const lowerUserMessage = Effect.fn("OpenAIChat.lowerUserMessage")(function* (
|
||||
message: OpenAIChatRequestMessage,
|
||||
options: LoweringOptions,
|
||||
@@ -461,9 +410,6 @@ const lowerAssistantMessage = Effect.fn("OpenAIChat.lowerAssistantMessage")(func
|
||||
if (observedField !== undefined) return observedField
|
||||
if (nativeReasoning !== undefined) return "reasoning_content"
|
||||
if (!fullyStructured || requireReasoning) return "reasoning_content"
|
||||
// Kimi always expects `reasoning_content` on replayed assistant messages,
|
||||
// even when thinking arrived only through structured details.
|
||||
if (details?.some(isKimiDetail)) return "reasoning_content"
|
||||
})()
|
||||
const reasoningText = (() => {
|
||||
if (configuredField !== undefined)
|
||||
@@ -935,74 +881,44 @@ const reasoningDelta = (
|
||||
return undefined
|
||||
}
|
||||
|
||||
const detailText = (details: ReadonlyArray<ReasoningDetail>, hideKimiSummary: boolean) => {
|
||||
const detailText = (details: ReadonlyArray<unknown>) => {
|
||||
const text = details.flatMap((detail) => {
|
||||
if (detail.type === "reasoning.text") return detail.text ? [detail.text] : []
|
||||
if (detail.type === "reasoning.summary") return detail.summary ? [detail.summary] : []
|
||||
// Kimi streams the full thinking through `reasoning_content` and a separate
|
||||
// summary through details; show the summary only when nothing else does.
|
||||
if (detail.type === "summary") return detail.summary && !hideKimiSummary ? [detail.summary] : []
|
||||
if (!isRecord(detail)) return []
|
||||
if (detail.type === "reasoning.text" && typeof detail.text === "string" && detail.text) return [detail.text]
|
||||
if (detail.type === "reasoning.summary" && typeof detail.summary === "string" && detail.summary)
|
||||
return [detail.summary]
|
||||
return []
|
||||
})
|
||||
if (text.length > 0) return text.join("")
|
||||
}
|
||||
|
||||
const appendReasoningDetails = (result: Array<ReasoningDetail>, details: ReadonlyArray<ReasoningDetail>) => {
|
||||
const appendReasoningDetails = (result: Array<unknown>, details: ReadonlyArray<unknown>) => {
|
||||
for (const detail of details) {
|
||||
const previous = result.at(-1)
|
||||
const merged = previous === undefined ? undefined : mergeReasoningDetails(previous, detail)
|
||||
if (merged === undefined) {
|
||||
if (
|
||||
!isRecord(previous) ||
|
||||
previous.type !== "reasoning.text" ||
|
||||
!isRecord(detail) ||
|
||||
detail.type !== "reasoning.text" ||
|
||||
conflictingReasoningTextDetails(previous, detail)
|
||||
) {
|
||||
result.push(detail)
|
||||
continue
|
||||
}
|
||||
result[result.length - 1] = merged
|
||||
result[result.length - 1] = {
|
||||
...previous,
|
||||
...Object.fromEntries(Object.entries(detail).filter((entry) => entry[1] !== undefined)),
|
||||
text: `${typeof previous.text === "string" ? previous.text : ""}${typeof detail.text === "string" ? detail.text : ""}`,
|
||||
signature: mergeDetailValue(previous.signature, detail.signature),
|
||||
format: mergeDetailValue(previous.format, detail.format),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Consecutive text or summary deltas of the same kind accumulate into one
|
||||
// entry; encrypted entries are opaque and never merge.
|
||||
const mergeReasoningDetails = (previous: ReasoningDetail, detail: ReasoningDetail): ReasoningDetail | undefined => {
|
||||
if (conflictingReasoningDetails(previous, detail)) return undefined
|
||||
if (previous.type === "reasoning.text" && detail.type === "reasoning.text")
|
||||
return {
|
||||
...previous,
|
||||
...detail,
|
||||
text: `${previous.text ?? ""}${detail.text ?? ""}`,
|
||||
...mergeDetailIdentity(previous, detail),
|
||||
}
|
||||
if (previous.type === "reasoning.summary" && detail.type === "reasoning.summary")
|
||||
return {
|
||||
...previous,
|
||||
...detail,
|
||||
summary: `${previous.summary ?? ""}${detail.summary ?? ""}`,
|
||||
...mergeDetailIdentity(previous, detail),
|
||||
}
|
||||
if (previous.type === "summary" && detail.type === "summary")
|
||||
return { ...previous, ...detail, summary: previous.summary + detail.summary }
|
||||
}
|
||||
|
||||
type DetailIdentity = {
|
||||
readonly id?: string | null
|
||||
readonly index?: number
|
||||
readonly format?: string
|
||||
readonly signature?: string | null
|
||||
}
|
||||
|
||||
// The first non-empty signature and format win; a later delta may carry the
|
||||
// signature for text that streamed earlier.
|
||||
const mergeDetailIdentity = (previous: DetailIdentity, current: DetailIdentity) => {
|
||||
const signature = mergeDetailValue(previous.signature, current.signature)
|
||||
const format = mergeDetailValue(previous.format, current.format)
|
||||
return {
|
||||
...(signature === undefined ? {} : { signature }),
|
||||
...(format === undefined ? {} : { format }),
|
||||
}
|
||||
}
|
||||
|
||||
const mergeDetailValue = <T>(previous: T | undefined, current: T | undefined) =>
|
||||
const mergeDetailValue = (previous: unknown, current: unknown) =>
|
||||
previous || current || (previous !== undefined ? previous : current)
|
||||
|
||||
const conflictingReasoningDetails = (previous: DetailIdentity, current: DetailIdentity) =>
|
||||
const conflictingReasoningTextDetails = (previous: Record<string, unknown>, current: Record<string, unknown>) =>
|
||||
conflictingDetailValue(previous.id, current.id) ||
|
||||
conflictingDetailValue(previous.index, current.index) ||
|
||||
conflictingDetailValue(previous.format, current.format) ||
|
||||
@@ -1014,7 +930,7 @@ const conflictingDetailValue = (previous: unknown, current: unknown) =>
|
||||
const reasoningMetadata = (
|
||||
providerMetadataKey: string,
|
||||
field: ParserState["reasoningField"],
|
||||
details?: ReadonlyArray<ReasoningDetail>,
|
||||
details?: ReadonlyArray<unknown>,
|
||||
) => ({
|
||||
[providerMetadataKey]: {
|
||||
...(field ? { reasoningField: field } : {}),
|
||||
@@ -1077,16 +993,11 @@ const step = (state: ParserState, event: OpenAIChatEvent) =>
|
||||
}
|
||||
|
||||
const reasoningField = state.reasoningField ?? reasoning?.field
|
||||
const reasoningTextObserved = state.reasoningTextObserved || reasoning !== undefined
|
||||
const detailDelta = Array.isArray(delta?.reasoning_details)
|
||||
? knownReasoningDetails(delta.reasoning_details)
|
||||
: undefined
|
||||
const detailDelta = Array.isArray(delta?.reasoning_details) ? delta.reasoning_details : undefined
|
||||
if (detailDelta !== undefined) appendReasoningDetails(state.reasoningDetails, detailDelta)
|
||||
const reasoningDetailsObserved = state.reasoningDetailsObserved || detailDelta !== undefined
|
||||
const deltaMetadata = reasoningMetadata(state.providerMetadataKey, reasoningField)
|
||||
const text = detailDelta?.length
|
||||
? (detailText(detailDelta, reasoningTextObserved) ?? reasoning?.text)
|
||||
: reasoning?.text
|
||||
const text = detailDelta?.length ? (detailText(detailDelta) ?? reasoning?.text) : reasoning?.text
|
||||
if (text !== undefined) lifecycle = Lifecycle.reasoningDelta(lifecycle, events, "reasoning-0", text, deltaMetadata)
|
||||
else if (
|
||||
reasoningDetailsObserved &&
|
||||
@@ -1182,7 +1093,6 @@ const step = (state: ParserState, event: OpenAIChatEvent) =>
|
||||
finishReason,
|
||||
lifecycle,
|
||||
reasoningField,
|
||||
reasoningTextObserved,
|
||||
reasoningDetails: state.reasoningDetails,
|
||||
reasoningDetailsObserved,
|
||||
reasoningEmitted,
|
||||
@@ -1263,7 +1173,6 @@ export const protocol = Protocol.make({
|
||||
toolCallEvents: [],
|
||||
lifecycle: Lifecycle.initial(),
|
||||
reasoningField: request.model.compatibility?.reasoningField,
|
||||
reasoningTextObserved: false,
|
||||
reasoningDetails: [],
|
||||
reasoningDetailsObserved: false,
|
||||
reasoningEmitted: false,
|
||||
|
||||
@@ -231,11 +231,11 @@ export const errorText = (error: unknown) => {
|
||||
|
||||
/**
|
||||
* `framing` step for Server-Sent Events. Decodes UTF-8, runs the SSE channel
|
||||
* decoder, optionally filters named events, and drops empty and bare `null`
|
||||
* events. `[DONE]` is dropped by default or retained for protocols that use it
|
||||
* as their stream boundary. Retry control events are ignored without
|
||||
* interrupting the stream. Decoder failures become provider output errors so
|
||||
* the public error channel stays `AIError`.
|
||||
* decoder, optionally filters named events, and drops empty events. `[DONE]`
|
||||
* is dropped by default or retained for protocols that use it as their stream
|
||||
* boundary. Retry control events are ignored without interrupting the stream.
|
||||
* Decoder failures become provider output errors so the public error channel
|
||||
* stays `AIError`.
|
||||
*/
|
||||
export const sseFraming = (
|
||||
bytes: Stream.Stream<Uint8Array, AIError>,
|
||||
@@ -265,10 +265,6 @@ export const sseFraming = (
|
||||
(event) =>
|
||||
(events === undefined || events.has(event.event)) &&
|
||||
event.data.length > 0 &&
|
||||
// Some OpenAI-compatible proxies serialize an empty flush as a bare
|
||||
// `data: null`, between events or after `[DONE]`. No protocol has a
|
||||
// null event, so it carries nothing and must not abort the stream.
|
||||
event.data !== "null" &&
|
||||
(event.data !== "[DONE]" || includeDone || (events !== undefined && event.event !== "message")),
|
||||
),
|
||||
Stream.map((event) => event.data),
|
||||
|
||||
@@ -89,7 +89,7 @@ export const optional = (secret: Secret | undefined, source = "optional value")
|
||||
? credential(Effect.fail(new MissingCredentialError(source)))
|
||||
: credentialFromSecret(secret, source)
|
||||
|
||||
export const config = (name: string) => credentialFromSecret(Config.redacted(name), name)
|
||||
export const config = (name: string) => credentialFromSecret(Config.Redacted(name), name)
|
||||
|
||||
export const effect = (load: Effect.Effect<Redacted.Redacted, CredentialError>) => credential(load)
|
||||
|
||||
|
||||
+28
-2
@@ -6,6 +6,7 @@ import type {
|
||||
ToolOutput as ToolOutputType,
|
||||
} from "./schema/index.js"
|
||||
import { ToolDefinition, ToolFailure, ToolOutput } from "./schema/index.js"
|
||||
import { isRecord } from "./utils/record.js"
|
||||
|
||||
/**
|
||||
* Schema constraint for tool parameters / success values: no decoding or
|
||||
@@ -200,7 +201,7 @@ export function make(config: TypedToolConfig | DynamicToolConfig): AnyTool {
|
||||
_definition: new ToolDefinition({
|
||||
name: "",
|
||||
description: config.description,
|
||||
inputSchema: toJsonSchema(config.parameters),
|
||||
inputSchema: toInputJsonSchema(config.parameters),
|
||||
outputSchema: toJsonSchema(config.success),
|
||||
}),
|
||||
}
|
||||
@@ -230,8 +231,33 @@ export const toDefinitions = (tools: Tools): ReadonlyArray<ToolDefinitionClass>
|
||||
}),
|
||||
)
|
||||
|
||||
const toInputJsonSchema = (schema: Schema.Top): JsonSchema.JsonSchema => {
|
||||
// Effect represents Struct({}) as any non-null value; tool parameters must
|
||||
// instead describe an object. Inline named empty inputs so providers such as
|
||||
// Gemini can recognize a no-argument tool, while retaining schema annotations.
|
||||
if (
|
||||
schema.ast._tag !== "Objects" ||
|
||||
schema.ast.propertySignatures.length !== 0 ||
|
||||
schema.ast.indexSignatures.length !== 0 ||
|
||||
schema.ast.encoding !== undefined ||
|
||||
schema.ast.checks !== undefined
|
||||
)
|
||||
return toJsonSchema(schema)
|
||||
|
||||
const json = Schema.toJsonSchemaDocument(schema, {
|
||||
onExcessProperty: "error",
|
||||
referencePolicy: () => undefined,
|
||||
}).schema
|
||||
if (isRecord(json.not) && json.not.type === "null" && Object.keys(json.not).length === 1) {
|
||||
const normalized: JsonSchema.JsonSchema = { type: "object", properties: {}, additionalProperties: false, ...json }
|
||||
delete normalized.not
|
||||
return normalized
|
||||
}
|
||||
return toJsonSchema(schema)
|
||||
}
|
||||
|
||||
const toJsonSchema = (schema: Schema.Top): JsonSchema.JsonSchema => {
|
||||
const document = Schema.toJsonSchemaDocument(schema)
|
||||
const document = Schema.toJsonSchemaDocument(schema, { onExcessProperty: "error" })
|
||||
if (Object.keys(document.definitions).length === 0) return document.schema
|
||||
return { ...document.schema, $defs: document.definitions }
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ type LanguageModel = {
|
||||
declare const auth: Auth.Definition
|
||||
declare const optionalAuthModel: LanguageModelFactory<BaseOptions, "optional", LanguageModel>
|
||||
declare const requiredAuthModel: LanguageModelFactory<BaseOptions, "required", LanguageModel>
|
||||
const configApiKey = Config.redacted("OPENAI_API_KEY")
|
||||
const configApiKey = Config.Redacted("OPENAI_API_KEY")
|
||||
|
||||
OpenAIChat.route.model({ id: "gpt-4.1-mini" })
|
||||
|
||||
|
||||
@@ -1182,9 +1182,7 @@ describe("OpenAI Chat route", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
// Only recognized detail shapes are retained and replayed; echoing an
|
||||
// undocumented provider payload is what breaks follow-up requests.
|
||||
it.effect("drops unknown reasoning details while using scalar display text", () =>
|
||||
it.effect("preserves unknown reasoning details while using scalar display text", () =>
|
||||
Effect.gen(function* () {
|
||||
const details = [{ type: "reasoning.future", format: "provider-v2", state: { opaque: true } }]
|
||||
const response = yield* LLMClient.generate(request).pipe(
|
||||
@@ -1201,195 +1199,16 @@ describe("OpenAI Chat route", () => {
|
||||
|
||||
expect(response.reasoning).toBe("thinking")
|
||||
expect(response.message.content.find((part) => part.type === "reasoning")?.providerMetadata).toEqual({
|
||||
openai: { reasoningField: "reasoning", reasoningDetails: [] },
|
||||
openai: { reasoningField: "reasoning", reasoningDetails: details },
|
||||
})
|
||||
|
||||
const replay = yield* compileRequest(LLM.request({ model, messages: [response.message] }))
|
||||
expect(replay.body.messages).toEqual([
|
||||
{ role: "assistant", content: "Hello", reasoning: "thinking", reasoning_details: [] },
|
||||
{ role: "assistant", content: "Hello", reasoning: "thinking", reasoning_details: details },
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
// Kimi's coding endpoint streams the full thinking through `reasoning_content`
|
||||
// and a separate summary + encrypted blob through its own `reasoning_details`
|
||||
// dialect. The stream-only `index` must not be echoed back.
|
||||
it.effect("merges Kimi summary deltas by index and replays details without the streaming index", () =>
|
||||
Effect.gen(function* () {
|
||||
const response = yield* LLMClient.generate(request).pipe(
|
||||
Effect.provide(
|
||||
fixedResponse(
|
||||
sseEvents(
|
||||
{ choices: [{ delta: { reasoning_content: "Let me" } }] },
|
||||
{ choices: [{ delta: { reasoning_content: " think" } }] },
|
||||
{ choices: [{ delta: { reasoning_details: [{ index: 0, type: "summary", summary: "Plan" }] } }] },
|
||||
{ choices: [{ delta: { reasoning_details: [{ index: 0, type: "summary", summary: " tools" }] } }] },
|
||||
{ choices: [{ delta: { reasoning_details: [{ index: 1, type: "encrypted", encrypted: "opaque" }] } }] },
|
||||
{
|
||||
choices: [
|
||||
{
|
||||
delta: {
|
||||
tool_calls: [
|
||||
{ index: 0, id: "call_1", type: "function", function: { name: "get_time", arguments: "{}" } },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ choices: [{ delta: {}, finish_reason: "tool_calls" }] },
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
const stored = [
|
||||
{ index: 0, type: "summary", summary: "Plan tools" },
|
||||
{ index: 1, type: "encrypted", encrypted: "opaque" },
|
||||
]
|
||||
expect(response.reasoning).toBe("Let me think")
|
||||
expect(response.message.content.find((part) => part.type === "reasoning")?.providerMetadata).toEqual({
|
||||
openai: { reasoningField: "reasoning_content", reasoningDetails: stored },
|
||||
})
|
||||
|
||||
const replay = yield* compileRequest(LLM.request({ model, messages: [response.message] }))
|
||||
expect(replay.body.messages).toEqual([
|
||||
{
|
||||
role: "assistant",
|
||||
content: null,
|
||||
tool_calls: [{ id: "call_1", type: "function", function: { name: "get_time", arguments: "{}" } }],
|
||||
reasoning_content: "Let me think",
|
||||
reasoning_details: [
|
||||
{ type: "summary", summary: "Plan tools" },
|
||||
{ type: "encrypted", encrypted: "opaque" },
|
||||
],
|
||||
},
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("displays Kimi summaries and replays reasoning_content when no scalar reasoning streams", () =>
|
||||
Effect.gen(function* () {
|
||||
const response = yield* LLMClient.generate(request).pipe(
|
||||
Effect.provide(
|
||||
fixedResponse(
|
||||
sseEvents(
|
||||
{ choices: [{ delta: { reasoning_details: [{ index: 0, type: "summary", summary: "Plan" }] } }] },
|
||||
{ choices: [{ delta: { reasoning_details: [{ index: 0, type: "summary", summary: " tools" }] } }] },
|
||||
{ choices: [{ delta: { reasoning_details: [{ index: 1, type: "encrypted", encrypted: "opaque" }] } }] },
|
||||
{ choices: [{ delta: { content: "Hello" } }] },
|
||||
{ choices: [{ delta: {}, finish_reason: "stop" }] },
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
expect(response.reasoning).toBe("Plan tools")
|
||||
|
||||
const replay = yield* compileRequest(LLM.request({ model, messages: [response.message] }))
|
||||
expect(replay.body.messages).toEqual([
|
||||
{
|
||||
role: "assistant",
|
||||
content: "Hello",
|
||||
reasoning_content: "Plan tools",
|
||||
reasoning_details: [
|
||||
{ type: "summary", summary: "Plan tools" },
|
||||
{ type: "encrypted", encrypted: "opaque" },
|
||||
],
|
||||
},
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
// Sessions persisted before the fix already hold Kimi details with `index`.
|
||||
it.effect("strips the streaming index from previously stored Kimi details", () =>
|
||||
Effect.gen(function* () {
|
||||
const replay = yield* compileRequest(
|
||||
LLM.request({
|
||||
model,
|
||||
messages: [
|
||||
Message.assistant([
|
||||
{
|
||||
type: "reasoning",
|
||||
text: "thinking",
|
||||
providerMetadata: {
|
||||
openai: {
|
||||
reasoningField: "reasoning_content",
|
||||
reasoningDetails: [
|
||||
{ index: 0, type: "summary", summary: "thinking" },
|
||||
{ index: 1, type: "encrypted", encrypted: "opaque" },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
]),
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
expect(replay.body.messages).toEqual([
|
||||
{
|
||||
role: "assistant",
|
||||
content: "",
|
||||
reasoning_content: "thinking",
|
||||
reasoning_details: [
|
||||
{ type: "summary", summary: "thinking" },
|
||||
{ type: "encrypted", encrypted: "opaque" },
|
||||
],
|
||||
},
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("merges consecutive OpenRouter summary deltas and replays them unmodified", () =>
|
||||
Effect.gen(function* () {
|
||||
const merged = [
|
||||
{ type: "reasoning.summary", summary: "Plan tools", format: "openai-responses-v1", index: 0 },
|
||||
{ type: "reasoning.encrypted", data: "opaque", format: "openai-responses-v1", index: 0 },
|
||||
]
|
||||
const response = yield* LLMClient.generate(request).pipe(
|
||||
Effect.provide(
|
||||
fixedResponse(
|
||||
sseEvents(
|
||||
{
|
||||
choices: [
|
||||
{
|
||||
delta: {
|
||||
reasoning_details: [
|
||||
{ type: "reasoning.summary", summary: "Plan", format: "openai-responses-v1", index: 0 },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
choices: [
|
||||
{
|
||||
delta: {
|
||||
reasoning_details: [
|
||||
{ type: "reasoning.summary", summary: " tools", format: "openai-responses-v1", index: 0 },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{ choices: [{ delta: { reasoning_details: [merged[1]] } }] },
|
||||
{ choices: [{ delta: { content: "Hello" } }] },
|
||||
{ choices: [{ delta: {}, finish_reason: "stop" }] },
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
expect(response.reasoning).toBe("Plan tools")
|
||||
expect(response.message.content.find((part) => part.type === "reasoning")?.providerMetadata).toEqual({
|
||||
openai: { reasoningDetails: merged },
|
||||
})
|
||||
|
||||
const replay = yield* compileRequest(LLM.request({ model, messages: [response.message] }))
|
||||
expect(replay.body.messages).toEqual([{ role: "assistant", content: "Hello", reasoning_details: merged }])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("uses scalar display text for signature-only reasoning details", () =>
|
||||
Effect.gen(function* () {
|
||||
const details = [{ type: "reasoning.text", signature: "signed", format: "provider-v2", index: 0 }]
|
||||
|
||||
@@ -375,27 +375,6 @@ describe("OpenAI-compatible Chat route", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("ignores bare null frames between deltas", () =>
|
||||
Effect.gen(function* () {
|
||||
const response = yield* LLMClient.generate(request).pipe(
|
||||
Effect.provide(
|
||||
fixedResponse(
|
||||
sseEvents(
|
||||
deltaChunk({ role: "assistant", content: "Hello" }),
|
||||
"null",
|
||||
deltaChunk({ content: "!" }),
|
||||
"null",
|
||||
deltaChunk({}, "stop"),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
expect(response.text).toBe("Hello!")
|
||||
expect(response.finishReason).toEqual({ normalized: "stop", raw: "stop" })
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("accepts nullable usage and preserves provider fields", () =>
|
||||
Effect.gen(function* () {
|
||||
const response = yield* LLMClient.generate(request).pipe(
|
||||
|
||||
@@ -393,33 +393,6 @@ describe("Open Responses-compatible route", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("ignores bare null frames between events", () =>
|
||||
Effect.gen(function* () {
|
||||
const model = configure({
|
||||
apiKey: "test-key",
|
||||
baseURL: "https://responses.example.test/v1",
|
||||
}).model("example-model")
|
||||
const response = yield* LLMClient.generate(LLM.request({ model, prompt: "Say hello." })).pipe(
|
||||
Effect.provide(
|
||||
fixedResponse(
|
||||
sseEvents(
|
||||
{ type: "response.output_item.added", output_index: 0, item: { type: "message", id: "msg_1" } },
|
||||
"null",
|
||||
{ type: "response.output_text.delta", output_index: 0, item_id: "msg_1", delta: "Hello" },
|
||||
"null",
|
||||
{ type: "response.output_item.done", output_index: 0, item: { type: "message", id: "msg_1" } },
|
||||
{ type: "response.completed", response: { id: "resp_1" } },
|
||||
"null",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
expect(response.text).toBe("Hello")
|
||||
expect(response.events.at(-1)).toMatchObject({ type: "finish" })
|
||||
}),
|
||||
)
|
||||
|
||||
describe("stream validation", () => {
|
||||
const request = LLM.request({
|
||||
model: configure({ apiKey: "test-key", baseURL: "https://responses.example.test/v1" }).model("example-model"),
|
||||
|
||||
@@ -315,9 +315,10 @@ describe("OpenRouter", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("drops unrecognized details and preserves duplicate continuation details", () =>
|
||||
it.effect("preserves opaque and duplicate continuation details", () =>
|
||||
Effect.gen(function* () {
|
||||
const details = [
|
||||
{ type: "reasoning.future", format: "provider-v2", state: { opaque: true } },
|
||||
{ type: "reasoning.encrypted", id: "state", data: "opaque" },
|
||||
{ type: "reasoning.encrypted", id: "state", data: "opaque" },
|
||||
]
|
||||
@@ -329,15 +330,7 @@ describe("OpenRouter", () => {
|
||||
Message.assistant({
|
||||
type: "reasoning",
|
||||
text: "Thinking",
|
||||
providerMetadata: {
|
||||
openrouter: {
|
||||
reasoningField: "reasoning",
|
||||
reasoningDetails: [
|
||||
{ type: "reasoning.future", format: "provider-v2", state: { opaque: true } },
|
||||
...details,
|
||||
],
|
||||
},
|
||||
},
|
||||
providerMetadata: { openrouter: { reasoningField: "reasoning", reasoningDetails: details } },
|
||||
}),
|
||||
],
|
||||
}),
|
||||
|
||||
@@ -178,20 +178,6 @@ describe("AI.Usage", () => {
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("sseFraming drops bare null frames and keeps other payloads", () =>
|
||||
Effect.gen(function* () {
|
||||
const frames = yield* ProviderShared.sseFraming(
|
||||
Stream.make(
|
||||
new TextEncoder().encode(
|
||||
'data: {"first":true}\n\ndata: null\n\nevent: update\ndata: null\n\ndata: "null"\n\ndata: 0\n\ndata: {"second":true}\n\ndata: [DONE]\n\ndata: null\n\n',
|
||||
),
|
||||
),
|
||||
).pipe(Stream.runCollect)
|
||||
|
||||
expect(Array.from(frames)).toEqual(['{"first":true}', '"null"', "0", '{"second":true}'])
|
||||
}),
|
||||
)
|
||||
|
||||
test("visibleOutputTokens clamps reasoning > output to zero", () => {
|
||||
expect(new Usage({ outputTokens: 10, reasoningTokens: 4 }).visibleOutputTokens).toBe(6)
|
||||
expect(new Usage({ outputTokens: 10 }).visibleOutputTokens).toBe(10)
|
||||
|
||||
@@ -1,13 +1,145 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Effect } from "effect"
|
||||
import { LLM } from "../src/index.js"
|
||||
import { OpenAIChat } from "../src/protocols.js"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { LLM, Tool } from "../src/index.js"
|
||||
import { AnthropicMessages, Gemini, OpenAIChat, OpenAIResponses } from "../src/protocols.js"
|
||||
import { ToolSchemaProjection } from "../src/protocols/utils/tool-schema.js"
|
||||
import { Auth } from "../src/route.js"
|
||||
import { compileRequest } from "../src/route/client.js"
|
||||
import { it } from "./lib/effect.js"
|
||||
|
||||
describe("tool schema projections", () => {
|
||||
test("only normalizes typed empty input structs, preserving raw schemas and output schemas", () => {
|
||||
const schema = { not: { type: "null" } }
|
||||
const definitions = Tool.toDefinitions({
|
||||
typed: Tool.make({
|
||||
description: "Typed",
|
||||
parameters: Schema.Struct({}),
|
||||
success: Schema.Struct({}),
|
||||
execute: () => Effect.succeed({}),
|
||||
}),
|
||||
raw: Tool.make({ description: "Raw", jsonSchema: schema, execute: () => Effect.succeed({}) }),
|
||||
})
|
||||
expect(definitions[0]?.inputSchema).toEqual({ type: "object", properties: {}, additionalProperties: false })
|
||||
expect(definitions[0]?.outputSchema).toEqual(schema)
|
||||
expect(definitions[1]?.inputSchema).toEqual(schema)
|
||||
})
|
||||
|
||||
test("retains empty input descriptions and preserves named outputs and explicit raw schemas", () => {
|
||||
const parameters = Schema.Struct({}).annotate({ identifier: "Ping", description: "No arguments" })
|
||||
const raw = { $ref: "#/$defs/Raw", $defs: { Raw: { not: { type: "null" }, description: "Raw schema" } } }
|
||||
const definitions = Tool.toDefinitions({
|
||||
typed: Tool.make({ description: "Ping", parameters, success: parameters, execute: () => Effect.succeed({}) }),
|
||||
raw: Tool.make({ description: "Raw", jsonSchema: raw, execute: () => Effect.succeed({}) }),
|
||||
})
|
||||
expect(definitions[0]?.inputSchema).toEqual({
|
||||
type: "object",
|
||||
properties: {},
|
||||
additionalProperties: false,
|
||||
description: "No arguments",
|
||||
})
|
||||
expect(definitions[0]?.outputSchema).toEqual({
|
||||
$ref: "#/$defs/Ping",
|
||||
$defs: { Ping: { not: { type: "null" }, description: "No arguments" } },
|
||||
})
|
||||
expect(definitions[1]?.inputSchema).toEqual(raw)
|
||||
})
|
||||
|
||||
const empty = { type: "object", properties: {}, additionalProperties: false }
|
||||
const nonempty = {
|
||||
type: "object",
|
||||
properties: { query: { type: "string" } },
|
||||
required: ["query"],
|
||||
additionalProperties: false,
|
||||
}
|
||||
const raw = { type: "object", properties: { value: { type: "number" } }, additionalProperties: true }
|
||||
|
||||
for (const scenario of [
|
||||
{
|
||||
route: OpenAIChat.route,
|
||||
tools: [empty, nonempty, raw].map((parameters, index) => ({
|
||||
type: "function",
|
||||
function: { name: ["ping", "lookup", "raw"][index], parameters },
|
||||
})),
|
||||
},
|
||||
{
|
||||
route: OpenAIResponses.route,
|
||||
tools: [empty, nonempty, raw].map((parameters, index) => ({
|
||||
type: "function",
|
||||
name: ["ping", "lookup", "raw"][index],
|
||||
parameters,
|
||||
})),
|
||||
},
|
||||
{
|
||||
route: AnthropicMessages.route,
|
||||
tools: [empty, nonempty, raw].map((input_schema, index) => ({
|
||||
name: ["ping", "lookup", "raw"][index],
|
||||
input_schema,
|
||||
})),
|
||||
},
|
||||
{
|
||||
route: Gemini.route,
|
||||
tools: [
|
||||
{
|
||||
functionDeclarations: [
|
||||
{ name: "ping", description: "Ping" },
|
||||
{
|
||||
name: "lookup",
|
||||
description: "Lookup",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: nonempty.properties,
|
||||
required: nonempty.required,
|
||||
},
|
||||
},
|
||||
{ name: "raw", description: "Raw", parameters: { type: "object", properties: raw.properties } },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]) {
|
||||
for (const input of [
|
||||
{ name: "plain", schema: Schema.Struct({}) },
|
||||
{ name: "described", schema: Schema.Struct({}).annotate({ description: "No arguments" }) },
|
||||
{ name: "named", schema: Schema.Struct({}).annotate({ identifier: "Ping" }) },
|
||||
{
|
||||
name: "named and described",
|
||||
schema: Schema.Struct({}).annotate({ identifier: "Ping", description: "No arguments" }),
|
||||
},
|
||||
]) {
|
||||
it.effect(
|
||||
`${scenario.route.id} prepares ${input.name} empty Effect Struct tools alongside nonempty and raw schemas`,
|
||||
() =>
|
||||
Effect.gen(function* () {
|
||||
const prepared = yield* compileRequest(
|
||||
LLM.request({
|
||||
model: scenario.route.with({ auth: Auth.bearer("test") }).model({ id: "test-model" }),
|
||||
prompt: "Use a tool.",
|
||||
tools: Tool.toDefinitions({
|
||||
ping: Tool.make({
|
||||
description: "Ping",
|
||||
parameters: input.schema,
|
||||
success: Schema.String,
|
||||
execute: () => Effect.succeed("pong"),
|
||||
}),
|
||||
lookup: Tool.make({
|
||||
description: "Lookup",
|
||||
parameters: Schema.Struct({ query: Schema.String }),
|
||||
success: Schema.String,
|
||||
execute: (input) => Effect.succeed(input.query),
|
||||
}),
|
||||
raw: Tool.make({ description: "Raw", jsonSchema: raw, execute: () => Effect.succeed("raw") }),
|
||||
}),
|
||||
}),
|
||||
)
|
||||
expect(prepared.body.tools).toMatchObject(scenario.tools)
|
||||
if (scenario.route.id === "gemini") {
|
||||
expect(prepared.body.tools).toEqual(scenario.tools)
|
||||
}
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
test("moonshot strips $ref siblings and converts tuple arrays to a schema object", () => {
|
||||
expect(
|
||||
ToolSchemaProjection.moonshot({
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
import { expect, test, type Page } from "@playwright/test"
|
||||
import { mockOpenCodeServer } from "../utils/mock-server"
|
||||
|
||||
const directory = "C:/Projects/providers-console-signin"
|
||||
|
||||
const project = {
|
||||
id: "proj_providers_console",
|
||||
canonical: directory,
|
||||
name: "Providers console",
|
||||
vcs: "git",
|
||||
time: { created: 1700000000000, updated: 1700000000000 },
|
||||
sandboxes: [],
|
||||
}
|
||||
|
||||
// Zen and the Console account share the id `opencode`: the provider comes from models.dev, the
|
||||
// integration is renamed by OpencodePlugin and carries the account sign-in.
|
||||
const zen = (paid: boolean) => ({
|
||||
id: "opencode",
|
||||
name: "OpenCode Zen",
|
||||
models: {
|
||||
"claude-sonnet-4-6": {
|
||||
id: "claude-sonnet-4-6",
|
||||
name: "Claude Sonnet 4.6",
|
||||
cost: { input: paid ? 3 : 0, output: 0 },
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const integrations = (connections: unknown[]) => [
|
||||
{
|
||||
id: "opencode",
|
||||
name: "OpenCode Console",
|
||||
methods: [
|
||||
{ id: "device", type: "oauth", label: "OpenCode Console account" },
|
||||
{ type: "key", label: "API key (service account)" },
|
||||
],
|
||||
connections,
|
||||
},
|
||||
{ id: "opencode-go", name: "OpenCode Go", methods: [{ type: "key" }], connections: [] },
|
||||
{ id: "anthropic", name: "Anthropic", methods: [{ type: "key" }], connections: [] },
|
||||
]
|
||||
|
||||
test.use({ viewport: { width: 1280, height: 900 } })
|
||||
|
||||
async function openProviders(page: Page, input: { paid: boolean; connections: unknown[] }) {
|
||||
await mockOpenCodeServer(page, {
|
||||
directory,
|
||||
project,
|
||||
provider: { all: [zen(input.paid)], connected: ["opencode"], default: {} },
|
||||
integrations: integrations(input.connections),
|
||||
sessions: [],
|
||||
pageMessages: () => ({ items: [] }),
|
||||
})
|
||||
await page.addInitScript((directory) => {
|
||||
localStorage.setItem(
|
||||
"opencode.global.dat:server",
|
||||
JSON.stringify({ projects: { local: [{ worktree: directory, expanded: true }] } }),
|
||||
)
|
||||
}, directory)
|
||||
await page.goto("/")
|
||||
await page.getByRole("button", { name: "Settings", exact: true }).click()
|
||||
const settings = page.getByTestId("settings-screen")
|
||||
await settings.getByRole("tab", { name: "Providers", exact: true }).click()
|
||||
await expect(settings.getByRole("heading", { name: "Popular providers" })).toBeVisible()
|
||||
return settings
|
||||
}
|
||||
|
||||
test("fresh install offers the Console sign-in", async ({ page }) => {
|
||||
const settings = await openProviders(page, { paid: false, connections: [] })
|
||||
await expect(settings.getByText("No connected providers")).toBeVisible()
|
||||
await expect(settings.getByText("OpenCode Console", { exact: true })).toBeVisible()
|
||||
})
|
||||
|
||||
test("a stored Zen API key keeps the Console sign-in available", async ({ page }) => {
|
||||
const settings = await openProviders(page, {
|
||||
paid: true,
|
||||
connections: [{ type: "credential", id: "cred_v1", label: "API key", method: "key" }],
|
||||
})
|
||||
const connected = settings.locator('[data-component="connected-providers-section"]')
|
||||
await expect(connected.getByText("OpenCode Zen", { exact: true })).toBeVisible()
|
||||
await expect(settings.getByText("OpenCode Console", { exact: true })).toBeVisible()
|
||||
})
|
||||
|
||||
test("a Console account hides the sign-in row", async ({ page }) => {
|
||||
const settings = await openProviders(page, {
|
||||
paid: true,
|
||||
connections: [{ type: "credential", id: "cred_account", label: "Clara Team", method: "oauth" }],
|
||||
})
|
||||
const connected = settings.locator('[data-component="connected-providers-section"]')
|
||||
await expect(connected.getByText("OpenCode Zen", { exact: true })).toBeVisible()
|
||||
// Anthropic only exists in the integration fixture, so its row proves the integration list has loaded.
|
||||
await expect(settings.getByText("Anthropic", { exact: true })).toBeVisible()
|
||||
await expect(settings.getByText("OpenCode Console", { exact: true })).toHaveCount(0)
|
||||
})
|
||||
@@ -9,7 +9,6 @@ export interface MockServerConfig {
|
||||
server?: string
|
||||
provider: unknown | (() => unknown)
|
||||
integrationMethods?: Record<string, unknown[]>
|
||||
integrations?: unknown[]
|
||||
onConnectKey?: (input: { integrationID: string; body: unknown }) => void
|
||||
shells?: unknown[]
|
||||
configEntries?: unknown[]
|
||||
@@ -259,13 +258,11 @@ function mockHandlers(config: MockServerConfig, state: { cursors: Map<string, st
|
||||
model: () => Effect.succeed({ location: location(config), data: currentModels(providerConfig(config)) }),
|
||||
modelDefault: () =>
|
||||
Effect.succeed({ location: location(config), data: currentDefaultModel(providerConfig(config)) }),
|
||||
integrationList: () => Effect.succeed({ location: location(config), data: config.integrations ?? [] }),
|
||||
integrationList: () => Effect.succeed({ location: location(config), data: [] }),
|
||||
integrationGet: (ctx) =>
|
||||
Effect.succeed({
|
||||
location: location(config),
|
||||
data: config.integrations
|
||||
?.filter(record)
|
||||
.find((integration) => integration.id === ctx.params.integrationID) ?? {
|
||||
data: {
|
||||
id: ctx.params.integrationID,
|
||||
name: ctx.params.integrationID,
|
||||
methods: config.integrationMethods?.[ctx.params.integrationID] ?? [{ type: "key", label: "API key" }],
|
||||
|
||||
@@ -45,7 +45,7 @@ const Current = Persistence.struct({ session: SessionsSchema })
|
||||
|
||||
export const ModelSelectionSchema = Persistence.migrate(
|
||||
Current,
|
||||
Schema.Struct({
|
||||
Persistence.legacy({
|
||||
session: Persistence.optional(Schema.Record(Schema.String, Schema.Unknown)),
|
||||
pick: Persistence.optional(Schema.Record(Schema.String, Schema.Unknown)),
|
||||
}).pipe(
|
||||
|
||||
@@ -32,7 +32,7 @@ describe("persistence schemas", () => {
|
||||
|
||||
test("legacy migration observes missing fields before initial defaults are applied", () => {
|
||||
const current = Persistence.struct({ mode: Schema.Literals(["compact", "full"]), enabled: Schema.Boolean })
|
||||
const stored = Schema.Struct({
|
||||
const stored = Persistence.legacy({
|
||||
mode: Schema.optional(Schema.Unknown),
|
||||
expanded: Schema.optional(Schema.Boolean),
|
||||
}).pipe(
|
||||
@@ -53,6 +53,38 @@ describe("persistence schemas", () => {
|
||||
expect(Schema.encodeSync(schema)(decode({ expanded: true }))).toEqual({ mode: "full", enabled: true })
|
||||
})
|
||||
|
||||
test("legacy read shapes carry unknown nested fields through to the current schema", () => {
|
||||
const current = Persistence.struct({
|
||||
general: Persistence.struct({
|
||||
mode: Schema.Literals(["compact", "full"]),
|
||||
theme: Schema.String,
|
||||
nested: Persistence.struct({ keep: Schema.Boolean }),
|
||||
}),
|
||||
other: Persistence.struct({ flag: Schema.Boolean }),
|
||||
})
|
||||
const stored = Persistence.legacy({
|
||||
general: Persistence.optional(Persistence.legacy({ expanded: Persistence.optional(Schema.Boolean) })),
|
||||
}).pipe(
|
||||
Schema.decode({
|
||||
decode: SchemaGetter.transform((value) => {
|
||||
const general = value.general
|
||||
if (!general || general.expanded === undefined) return value
|
||||
return { ...value, general: { ...general, mode: general.expanded ? "full" : "compact" } }
|
||||
}),
|
||||
encode: SchemaGetter.passthrough(),
|
||||
}),
|
||||
)
|
||||
const schema = Persistence.withInitial(Persistence.migrate(current, stored), {
|
||||
general: { mode: "compact", theme: "light", nested: { keep: false } },
|
||||
other: { flag: false },
|
||||
})
|
||||
const decode = Schema.decodeUnknownSync(schema)
|
||||
expect(decode({ general: { expanded: true, theme: "dark", nested: { keep: true } }, other: { flag: true } })).toEqual({
|
||||
general: { mode: "full", theme: "dark", nested: { keep: true } },
|
||||
other: { flag: true },
|
||||
})
|
||||
})
|
||||
|
||||
test("initial merging preserves field codecs and replaces arrays rather than merging indexes", () => {
|
||||
const current = Persistence.struct({
|
||||
amount: Schema.NumberFromString.check(Schema.isFinite()),
|
||||
|
||||
@@ -23,13 +23,11 @@ export function withInitial<S extends Schema.ConstraintCodec<object, unknown>>(
|
||||
initial: NoInfer<S["Type"]>,
|
||||
) {
|
||||
const schema = isMigrated(definition) ? definition.current : definition
|
||||
const read = isMigrated(definition)
|
||||
? SchemaParser.decodeUnknownResult(definition.read, { onExcessProperty: "preserve" })
|
||||
: Result.succeed<unknown>
|
||||
const read = isMigrated(definition) ? SchemaParser.decodeUnknownResult(definition.read) : Result.succeed<unknown>
|
||||
const encode = Schema.encodeUnknownSync(schema)
|
||||
return Schema.Unknown.pipe(
|
||||
Schema.decode<Schema.Unknown>({
|
||||
decode: SchemaGetter.transformOrFail((value) =>
|
||||
decode: SchemaGetter.transformEffect((value) =>
|
||||
Effect.fromResult(Result.map(read(value), (stored) => merge(initial, recover(schema.ast, stored, initial)))),
|
||||
),
|
||||
encode: SchemaGetter.transform((value) => encode(value)),
|
||||
@@ -38,6 +36,12 @@ export function withInitial<S extends Schema.ConstraintCodec<object, unknown>>(
|
||||
)
|
||||
}
|
||||
|
||||
// A legacy read shape declares only the fields it migrates. Decoding strips unknown keys, so every
|
||||
// struct level in a `migrate` read schema must stay open for the current fields it does not name.
|
||||
export function legacy<const Fields extends Schema.Struct.Fields>(fields: Fields) {
|
||||
return Schema.StructWithRest(Schema.Struct(fields), [Schema.Record(Schema.String, Schema.Unknown)])
|
||||
}
|
||||
|
||||
// Object-level codecs own their recovery. Plain structs can recover fields independently.
|
||||
function recover(ast: SchemaAST.AST, value: unknown, initial: unknown): unknown {
|
||||
if (value === undefined) return initial
|
||||
|
||||
@@ -93,7 +93,7 @@ describe("normalizeProviderList", () => {
|
||||
|
||||
describe("normalizeProjectInfo", () => {
|
||||
test("keeps the project VCS backend", () => {
|
||||
const project = { id: "prj", canonical: "/repo", time: { created: 1, updated: 1, active: 1 }, sandboxes: [] }
|
||||
const project = { id: "prj", canonical: "/repo", time: { created: 1, updated: 1 }, sandboxes: [] }
|
||||
expect(normalizeProjectInfo({ ...project, vcs: "git" } as Project).vcs).toBe("git")
|
||||
expect(normalizeProjectInfo({ ...project, vcs: "hg" } as Project).vcs).toBe("hg")
|
||||
expect(normalizeProjectInfo(project as Project).vcs).toBeUndefined()
|
||||
@@ -124,7 +124,7 @@ describe("updateProjectInfo", () => {
|
||||
canonical: "/repo",
|
||||
name: "Repo",
|
||||
icon: { color: "purple" },
|
||||
time: { created: 1, updated: 2, active: 2 },
|
||||
time: { created: 1, updated: 2 },
|
||||
sandboxes: ["/repo-sandbox"],
|
||||
} satisfies Project
|
||||
|
||||
|
||||
@@ -99,13 +99,13 @@ describe("readLocalImage", () => {
|
||||
test.each([400, 401])("propagates declared API errors (%s)", async (status) => {
|
||||
const error = { _tag: "RequestError", message: "Cannot read image" }
|
||||
const { api } = setup(() => Response.json(error, { status }))
|
||||
await expect(readLocalImage(api, "/repo", "image.png", new AbortController().signal)).rejects.toMatchObject(error)
|
||||
await expect(readLocalImage(api, "/repo", "image.png", new AbortController().signal)).rejects.toEqual(error)
|
||||
})
|
||||
|
||||
test("propagates missing-file errors", async () => {
|
||||
const error = { _tag: "FileNotFoundError", path: "image.png", message: "File not found: image.png" }
|
||||
const { api } = setup(() => Response.json(error, { status: 404 }))
|
||||
await expect(readLocalImage(api, "/repo", "image.png", new AbortController().signal)).rejects.toMatchObject(error)
|
||||
await expect(readLocalImage(api, "/repo", "image.png", new AbortController().signal)).rejects.toEqual(error)
|
||||
})
|
||||
|
||||
test("does not turn an unexpected HTTP status into a Blob", async () => {
|
||||
|
||||
@@ -53,7 +53,7 @@ const State = Persistence.struct({
|
||||
export function serverState(canonicalLocalServer: () => string | undefined = () => undefined) {
|
||||
return Persistence.migrate(
|
||||
State,
|
||||
Schema.Struct({ projects: Projects, lastProject: LastProject }).pipe(
|
||||
Persistence.legacy({ projects: Projects, lastProject: LastProject }).pipe(
|
||||
Schema.decode({
|
||||
decode: SchemaGetter.transform((value) => {
|
||||
const canonical = canonicalLocalServer()
|
||||
|
||||
@@ -188,9 +188,9 @@ function legacyTimelineActivity(value: boolean | "hidden" | "compact" | "full" |
|
||||
|
||||
export const settingsPersistence = Persistence.migrate(
|
||||
settingsSchema,
|
||||
Schema.Struct({
|
||||
Persistence.legacy({
|
||||
general: Persistence.optional(
|
||||
Schema.Struct({
|
||||
Persistence.legacy({
|
||||
// Keep invalid explicit values distinct from absent values so legacy preferences cannot replace them.
|
||||
timelineDetail: Schema.optional(
|
||||
Schema.NullOr(
|
||||
|
||||
@@ -8,7 +8,6 @@ import { useIntegrations } from "@/providers/catalog/integrations"
|
||||
import { createMemo, type Component, For, Show } from "solid-js"
|
||||
import { useLanguage } from "@/runtime/i18n/language"
|
||||
import { useServerSDK } from "@/runtime/server/client"
|
||||
import { CONSOLE_INTEGRATION } from "@/providers/connect/controller"
|
||||
import { DialogConnectProvider, useProviderConnectController } from "@/providers/connect/dialog"
|
||||
import { SettingsList } from "@/settings/list"
|
||||
import "@/settings/settings.css"
|
||||
@@ -63,17 +62,9 @@ export const SettingsProviders: Component<{
|
||||
|
||||
const popular = createMemo(() => {
|
||||
const connectedIDs = new Set(connected().map((p) => p.id))
|
||||
// The Console account (integration `opencode`) shares its id with the Zen provider. A stored API
|
||||
// key, including one imported from a v1 auth.json, makes Zen "connected" without any account, so
|
||||
// the Popular list keeps the sign-in row until the active credential is an OAuth grant. Until the
|
||||
// integration list arrives the row is still the models.dev Zen provider, so dedupe it as before.
|
||||
const console = integrations.list().find((entry) => entry.id === CONSOLE_INTEGRATION)
|
||||
const items = providers
|
||||
.popular()
|
||||
.filter((p) => {
|
||||
if (p.id !== CONSOLE_INTEGRATION || !console) return !connectedIDs.has(p.id)
|
||||
return console.connections.find((connection) => connection.type === "credential")?.method !== "oauth"
|
||||
})
|
||||
.filter((p) => !connectedIDs.has(p.id))
|
||||
.slice()
|
||||
items.sort((a, b) => popularProviders.indexOf(a.id) - popularProviders.indexOf(b.id))
|
||||
return items
|
||||
|
||||
@@ -24,7 +24,7 @@ test("settings project inventory reads metadata without acquiring directory stor
|
||||
name: `Project ${index}`,
|
||||
icon: { color: "orange" },
|
||||
commands: { start: "bun install" },
|
||||
time: { created: 1, updated: 1, active: 1 },
|
||||
time: { created: 1, updated: 1 },
|
||||
sandboxes: [],
|
||||
worktrees: [],
|
||||
}))
|
||||
|
||||
@@ -176,16 +176,16 @@ export const layoutSchema = Persistence.struct({
|
||||
|
||||
export const layoutPersistence = Persistence.migrate(
|
||||
layoutSchema,
|
||||
Schema.Struct({
|
||||
Persistence.legacy({
|
||||
sidebar: Persistence.optional(
|
||||
Schema.Struct({
|
||||
Persistence.legacy({
|
||||
workspaces: Persistence.optional(Schema.Union([Schema.Boolean, Schema.Record(Schema.String, Schema.Boolean)])),
|
||||
workspacesDefault: Persistence.optional(Schema.Boolean),
|
||||
}),
|
||||
),
|
||||
review: Persistence.optional(Schema.Struct({ panelOpened: Persistence.optional(Schema.Boolean) })),
|
||||
review: Persistence.optional(Persistence.legacy({ panelOpened: Persistence.optional(Schema.Boolean) })),
|
||||
fileTree: Persistence.optional(
|
||||
Schema.Struct({
|
||||
Persistence.legacy({
|
||||
opened: Persistence.optional(Schema.Boolean),
|
||||
width: Persistence.optional(Schema.Finite),
|
||||
tab: Persistence.optional(Schema.Literals(["changes", "all"])),
|
||||
|
||||
@@ -107,7 +107,7 @@ describe("withWorktreeInventory", () => {
|
||||
id: "project",
|
||||
canonical: "/repo",
|
||||
name: "Before",
|
||||
time: { created: 1, updated: 1, active: 1 },
|
||||
time: { created: 1, updated: 1 },
|
||||
sandboxes: [],
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import { Schema } from "effect"
|
||||
import { Spec } from "../framework/spec"
|
||||
import { Updater } from "../services/updater"
|
||||
|
||||
export const PrintLogs = GlobalFlag.setting("print-logs")({
|
||||
flag: Flag.boolean("print-logs").pipe(
|
||||
export const PrintLogs = GlobalFlag.Setting("print-logs")({
|
||||
flag: Flag.Boolean("print-logs").pipe(
|
||||
Flag.withDescription("Print logs to stderr (server logs require --standalone)"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
@@ -13,23 +13,23 @@ export const PrintLogs = GlobalFlag.setting("print-logs")({
|
||||
declare const OPENCODE_CLI_NAME: string | undefined
|
||||
|
||||
const ServerParams = {
|
||||
standalone: Flag.boolean("standalone").pipe(
|
||||
standalone: Flag.Boolean("standalone").pipe(
|
||||
Flag.withDescription("Run with a private server instead of the background service"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
server: Flag.string("server").pipe(
|
||||
server: Flag.String("server").pipe(
|
||||
Flag.withDescription("Connect to a server URL instead of the background service"),
|
||||
Flag.optional,
|
||||
),
|
||||
}
|
||||
|
||||
const PermissionParams = {
|
||||
auto: Flag.boolean("auto").pipe(
|
||||
auto: Flag.Boolean("auto").pipe(
|
||||
Flag.withDescription("Auto-approve permissions that are not explicitly denied"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
yolo: Flag.boolean("yolo").pipe(Flag.withDefault(false), Flag.withHidden),
|
||||
dangerouslySkipPermissions: Flag.boolean("dangerously-skip-permissions").pipe(
|
||||
yolo: Flag.Boolean("yolo").pipe(Flag.withDefault(false), Flag.withHidden),
|
||||
dangerouslySkipPermissions: Flag.Boolean("dangerously-skip-permissions").pipe(
|
||||
Flag.withDefault(false),
|
||||
Flag.withHidden,
|
||||
),
|
||||
@@ -40,32 +40,32 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
params: {
|
||||
...ServerParams,
|
||||
...PermissionParams,
|
||||
directory: Argument.string("directory").pipe(
|
||||
directory: Argument.String("directory").pipe(
|
||||
Argument.withDescription("Directory to start OpenCode in"),
|
||||
Argument.optional,
|
||||
),
|
||||
continue: Flag.boolean("continue").pipe(
|
||||
continue: Flag.Boolean("continue").pipe(
|
||||
Flag.withAlias("c"),
|
||||
Flag.withDescription("Continue the last session"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
session: Flag.string("session").pipe(
|
||||
session: Flag.String("session").pipe(
|
||||
Flag.withAlias("s"),
|
||||
Flag.withDescription("Session ID to continue"),
|
||||
Flag.optional,
|
||||
),
|
||||
prompt: Flag.string("prompt").pipe(Flag.withDescription("Prompt to use"), Flag.optional),
|
||||
prompt: Flag.String("prompt").pipe(Flag.withDescription("Prompt to use"), Flag.optional),
|
||||
},
|
||||
commands: [
|
||||
Spec.make("upgrade", {
|
||||
description: "Upgrade OpenCode to the latest or a specific version",
|
||||
aliases: ["update"],
|
||||
params: {
|
||||
target: Argument.string("target").pipe(
|
||||
target: Argument.String("target").pipe(
|
||||
Argument.withDescription("Version to upgrade to (with or without a leading v)"),
|
||||
Argument.optional,
|
||||
),
|
||||
method: Flag.choice("method", Updater.methods).pipe(
|
||||
method: Flag.Literals("method", Updater.methods).pipe(
|
||||
Flag.withAlias("m"),
|
||||
Flag.withDescription("Installation method to use"),
|
||||
Flag.optional,
|
||||
@@ -75,21 +75,21 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("uninstall", {
|
||||
description: "Uninstall OpenCode and remove all related files",
|
||||
params: {
|
||||
keepConfig: Flag.boolean("keep-config").pipe(
|
||||
keepConfig: Flag.Boolean("keep-config").pipe(
|
||||
Flag.withAlias("c"),
|
||||
Flag.withDescription("Keep configuration files"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
keepData: Flag.boolean("keep-data").pipe(
|
||||
keepData: Flag.Boolean("keep-data").pipe(
|
||||
Flag.withAlias("d"),
|
||||
Flag.withDescription("Keep session data and snapshots"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
dryRun: Flag.boolean("dry-run").pipe(
|
||||
dryRun: Flag.Boolean("dry-run").pipe(
|
||||
Flag.withDescription("Show what would be removed without removing"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
force: Flag.boolean("force").pipe(
|
||||
force: Flag.Boolean("force").pipe(
|
||||
Flag.withAlias("f"),
|
||||
Flag.withDescription("Skip confirmation prompts"),
|
||||
Flag.withDefault(false),
|
||||
@@ -101,17 +101,17 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
description: "Make a request to the running server",
|
||||
params: {
|
||||
...ServerParams,
|
||||
request: Argument.string("operation | method path").pipe(
|
||||
request: Argument.String("operation | method path").pipe(
|
||||
Argument.withDescription("OpenAPI operation ID, or an HTTP method followed by a path"),
|
||||
Argument.variadic({ min: 1, max: 2 }),
|
||||
),
|
||||
data: Flag.string("data").pipe(Flag.withAlias("d"), Flag.withDescription("Request body"), Flag.optional),
|
||||
header: Flag.string("header").pipe(
|
||||
data: Flag.String("data").pipe(Flag.withAlias("d"), Flag.withDescription("Request body"), Flag.optional),
|
||||
header: Flag.String("header").pipe(
|
||||
Flag.withAlias("H"),
|
||||
Flag.withDescription("Request header in name:value form"),
|
||||
Flag.atMost(100),
|
||||
),
|
||||
param: Flag.keyValuePair("param").pipe(Flag.withDescription("OpenAPI path or query parameter"), Flag.optional),
|
||||
param: Flag.KeyValuePair("param").pipe(Flag.withDescription("OpenAPI path or query parameter"), Flag.optional),
|
||||
},
|
||||
}),
|
||||
Spec.make("debug", {
|
||||
@@ -122,7 +122,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("paths", {
|
||||
description: "Show global paths (data, config, cache, state)",
|
||||
params: {
|
||||
name: Argument.choice("name", [
|
||||
name: Argument.Literals("name", [
|
||||
"db",
|
||||
"home",
|
||||
"data",
|
||||
@@ -134,7 +134,9 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
"log",
|
||||
"repos",
|
||||
]).pipe(
|
||||
Argument.withDescription("Print only one path: db, home, data, config, cache, state, tmp, bin, log, repos"),
|
||||
Argument.withDescription(
|
||||
"Print only one path: db, home, data, config, cache, state, tmp, bin, log, repos",
|
||||
),
|
||||
Argument.optional,
|
||||
),
|
||||
},
|
||||
@@ -148,7 +150,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
description: "list providers and credentials",
|
||||
params: {
|
||||
...ServerParams,
|
||||
format: Flag.choice("format", ["default", "json"]).pipe(
|
||||
format: Flag.Literals("format", ["default", "json"]).pipe(
|
||||
Flag.withDescription("Output format"),
|
||||
Flag.withDefault("default"),
|
||||
),
|
||||
@@ -158,12 +160,12 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
description: "log in to a provider",
|
||||
params: {
|
||||
...ServerParams,
|
||||
target: Argument.string("target").pipe(
|
||||
target: Argument.String("target").pipe(
|
||||
Argument.withDescription("Integration ID, name, or well-known provider URL"),
|
||||
Argument.optional,
|
||||
),
|
||||
method: Flag.string("method").pipe(Flag.withDescription("Authentication method ID"), Flag.optional),
|
||||
answer: Flag.string("answer").pipe(
|
||||
method: Flag.String("method").pipe(Flag.withDescription("Authentication method ID"), Flag.optional),
|
||||
answer: Flag.String("answer").pipe(
|
||||
Flag.withDescription("Provider form answer (key=value; repeat for multiple fields)"),
|
||||
Flag.atMost(100),
|
||||
),
|
||||
@@ -173,11 +175,11 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
description: "log out of a saved account",
|
||||
params: {
|
||||
...ServerParams,
|
||||
target: Argument.string("target").pipe(
|
||||
target: Argument.String("target").pipe(
|
||||
Argument.withDescription("Integration ID or name"),
|
||||
Argument.optional,
|
||||
),
|
||||
credential: Argument.string("credential").pipe(
|
||||
credential: Argument.String("credential").pipe(
|
||||
Argument.withDescription("Credential ID or label (opens an account picker when omitted)"),
|
||||
Argument.optional,
|
||||
),
|
||||
@@ -187,11 +189,11 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
description: "switch the active account for an integration",
|
||||
params: {
|
||||
...ServerParams,
|
||||
target: Argument.string("target").pipe(
|
||||
target: Argument.String("target").pipe(
|
||||
Argument.withDescription("Integration ID or name"),
|
||||
Argument.optional,
|
||||
),
|
||||
credential: Argument.string("credential").pipe(
|
||||
credential: Argument.String("credential").pipe(
|
||||
Argument.withDescription("Credential ID or label (opens an account picker when omitted)"),
|
||||
Argument.optional,
|
||||
),
|
||||
@@ -206,21 +208,21 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("add", {
|
||||
description: "Add an MCP server to your configuration",
|
||||
params: {
|
||||
name: Argument.string("name").pipe(Argument.withDescription("Name of the MCP server")),
|
||||
command: Argument.string("command").pipe(
|
||||
name: Argument.String("name").pipe(Argument.withDescription("Name of the MCP server")),
|
||||
command: Argument.String("command").pipe(
|
||||
Argument.withDescription("Command and arguments for a local server, passed after --"),
|
||||
Argument.variadic({ min: 0 }),
|
||||
),
|
||||
url: Flag.string("url").pipe(Flag.withDescription("URL for a remote MCP server"), Flag.optional),
|
||||
header: Flag.keyValuePair("header").pipe(
|
||||
url: Flag.String("url").pipe(Flag.withDescription("URL for a remote MCP server"), Flag.optional),
|
||||
header: Flag.KeyValuePair("header").pipe(
|
||||
Flag.withDescription("HTTP header for a remote server, as name=value"),
|
||||
Flag.optional,
|
||||
),
|
||||
env: Flag.keyValuePair("env").pipe(
|
||||
env: Flag.KeyValuePair("env").pipe(
|
||||
Flag.withDescription("Environment variable for a local server, as name=value"),
|
||||
Flag.optional,
|
||||
),
|
||||
global: Flag.boolean("global").pipe(
|
||||
global: Flag.Boolean("global").pipe(
|
||||
Flag.withDescription("Write to the global config instead of the project config"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
@@ -228,11 +230,11 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
}),
|
||||
Spec.make("auth", {
|
||||
description: "Authenticate with an OAuth-capable remote MCP server",
|
||||
params: { name: Argument.string("name").pipe(Argument.withDescription("Name of the MCP server")) },
|
||||
params: { name: Argument.String("name").pipe(Argument.withDescription("Name of the MCP server")) },
|
||||
}),
|
||||
Spec.make("logout", {
|
||||
description: "Remove stored OAuth credentials for an MCP server",
|
||||
params: { name: Argument.string("name").pipe(Argument.withDescription("Name of the MCP server")) },
|
||||
params: { name: Argument.String("name").pipe(Argument.withDescription("Name of the MCP server")) },
|
||||
}),
|
||||
],
|
||||
}),
|
||||
@@ -242,7 +244,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("list", {
|
||||
description: "List plugins",
|
||||
params: {
|
||||
builtin: Flag.boolean("builtin").pipe(
|
||||
builtin: Flag.Boolean("builtin").pipe(
|
||||
Flag.withDescription("Include built-in server plugins"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
@@ -251,13 +253,13 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("add", {
|
||||
description: "Install a plugin and add it to the global configuration",
|
||||
params: {
|
||||
package: Argument.string("package").pipe(Argument.withDescription("npm registry or Git package specifier")),
|
||||
package: Argument.String("package").pipe(Argument.withDescription("npm registry or Git package specifier")),
|
||||
},
|
||||
}),
|
||||
Spec.make("check", {
|
||||
description: "Check package plugins for updates",
|
||||
params: {
|
||||
target: Argument.string("target").pipe(
|
||||
target: Argument.String("target").pipe(
|
||||
Argument.withDescription("Configured package target"),
|
||||
Argument.optional,
|
||||
),
|
||||
@@ -266,7 +268,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("update", {
|
||||
description: "Update package plugins",
|
||||
params: {
|
||||
target: Argument.string("target").pipe(
|
||||
target: Argument.String("target").pipe(
|
||||
Argument.withDescription("Configured package target; omit to update all outdated plugins"),
|
||||
Argument.optional,
|
||||
),
|
||||
@@ -275,7 +277,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("remove", {
|
||||
description: "Remove a plugin from global configuration",
|
||||
params: {
|
||||
package: Argument.string("package").pipe(Argument.withDescription("configured package specifier")),
|
||||
package: Argument.String("package").pipe(Argument.withDescription("configured package specifier")),
|
||||
},
|
||||
}),
|
||||
],
|
||||
@@ -288,108 +290,108 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
description: "Show shareable usage statistics",
|
||||
params: {
|
||||
...ServerParams,
|
||||
days: Flag.integer("days").pipe(
|
||||
days: Flag.Int("days").pipe(
|
||||
Flag.withSchema(Schema.Int.check(Schema.isGreaterThanOrEqualTo(0))),
|
||||
Flag.withDescription("Show the last N days; 0 means today"),
|
||||
Flag.optional,
|
||||
),
|
||||
year: Flag.integer("year").pipe(
|
||||
year: Flag.Int("year").pipe(
|
||||
Flag.withSchema(Schema.Int.check(Schema.isBetween({ minimum: 1970, maximum: 9_999 }))),
|
||||
Flag.withDescription("Show a calendar year"),
|
||||
Flag.optional,
|
||||
),
|
||||
all: Flag.boolean("all").pipe(Flag.withDescription("Show lifetime statistics"), Flag.withDefault(false)),
|
||||
project: Flag.string("project").pipe(
|
||||
all: Flag.Boolean("all").pipe(Flag.withDescription("Show lifetime statistics"), Flag.withDefault(false)),
|
||||
project: Flag.String("project").pipe(
|
||||
Flag.withDescription('Filter by project ID, or use "." for the current project'),
|
||||
Flag.optional,
|
||||
),
|
||||
models: Flag.boolean("models").pipe(Flag.withDescription("Show model usage"), Flag.withDefault(false)),
|
||||
tools: Flag.boolean("tools").pipe(Flag.withDescription("Show tool reliability"), Flag.withDefault(false)),
|
||||
cost: Flag.boolean("cost").pipe(Flag.withDescription("Show cost and token details"), Flag.withDefault(false)),
|
||||
full: Flag.boolean("full").pipe(Flag.withDescription("Show every detailed section"), Flag.withDefault(false)),
|
||||
limit: Flag.integer("limit").pipe(
|
||||
models: Flag.Boolean("models").pipe(Flag.withDescription("Show model usage"), Flag.withDefault(false)),
|
||||
tools: Flag.Boolean("tools").pipe(Flag.withDescription("Show tool reliability"), Flag.withDefault(false)),
|
||||
cost: Flag.Boolean("cost").pipe(Flag.withDescription("Show cost and token details"), Flag.withDefault(false)),
|
||||
full: Flag.Boolean("full").pipe(Flag.withDescription("Show every detailed section"), Flag.withDefault(false)),
|
||||
limit: Flag.Int("limit").pipe(
|
||||
Flag.withSchema(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))),
|
||||
Flag.withDescription("Number of rows in detailed sections"),
|
||||
Flag.withDefault(5),
|
||||
),
|
||||
json: Flag.boolean("json").pipe(Flag.withDescription("Output statistics as JSON"), Flag.withDefault(false)),
|
||||
json: Flag.Boolean("json").pipe(Flag.withDescription("Output statistics as JSON"), Flag.withDefault(false)),
|
||||
},
|
||||
}),
|
||||
Spec.make("mini", {
|
||||
description: "Start the minimal interactive interface",
|
||||
params: {
|
||||
...ServerParams,
|
||||
continue: Flag.boolean("continue").pipe(
|
||||
continue: Flag.Boolean("continue").pipe(
|
||||
Flag.withAlias("c"),
|
||||
Flag.withDescription("Continue the last session"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
session: Flag.string("session").pipe(
|
||||
session: Flag.String("session").pipe(
|
||||
Flag.withAlias("s"),
|
||||
Flag.withDescription("Session ID to continue"),
|
||||
Flag.optional,
|
||||
),
|
||||
fork: Flag.boolean("fork").pipe(
|
||||
fork: Flag.Boolean("fork").pipe(
|
||||
Flag.withDescription("Fork the session when continuing"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
replay: Flag.boolean("replay").pipe(
|
||||
replay: Flag.Boolean("replay").pipe(
|
||||
Flag.withDescription("Restore session history on resume and resize (disable with --no-replay)"),
|
||||
Flag.optional,
|
||||
),
|
||||
replayLimit: Flag.integer("replay-limit").pipe(
|
||||
replayLimit: Flag.Int("replay-limit").pipe(
|
||||
Flag.withDescription("Limit replay to the newest N messages (default: 200)"),
|
||||
Flag.optional,
|
||||
),
|
||||
model: Flag.string("model").pipe(
|
||||
model: Flag.String("model").pipe(
|
||||
Flag.withAlias("m"),
|
||||
Flag.withDescription("Model to use in the format provider/model"),
|
||||
Flag.optional,
|
||||
),
|
||||
agent: Flag.string("agent").pipe(Flag.withDescription("Agent to use"), Flag.optional),
|
||||
prompt: Flag.string("prompt").pipe(Flag.withDescription("Prompt to use"), Flag.optional),
|
||||
demo: Flag.boolean("demo").pipe(Flag.withDefault(false), Flag.withHidden),
|
||||
agent: Flag.String("agent").pipe(Flag.withDescription("Agent to use"), Flag.optional),
|
||||
prompt: Flag.String("prompt").pipe(Flag.withDescription("Prompt to use"), Flag.optional),
|
||||
demo: Flag.Boolean("demo").pipe(Flag.withDefault(false), Flag.withHidden),
|
||||
},
|
||||
}),
|
||||
Spec.make("run", {
|
||||
description: "Run OpenCode with a message",
|
||||
params: {
|
||||
...ServerParams,
|
||||
message: Argument.string("message").pipe(
|
||||
message: Argument.String("message").pipe(
|
||||
Argument.withDescription("Message to send"),
|
||||
Argument.variadic({ min: 0 }),
|
||||
),
|
||||
continue: Flag.boolean("continue").pipe(
|
||||
continue: Flag.Boolean("continue").pipe(
|
||||
Flag.withAlias("c"),
|
||||
Flag.withDescription("Continue the last session"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
session: Flag.string("session").pipe(
|
||||
session: Flag.String("session").pipe(
|
||||
Flag.withAlias("s"),
|
||||
Flag.withDescription("Session ID to continue"),
|
||||
Flag.optional,
|
||||
),
|
||||
fork: Flag.boolean("fork").pipe(
|
||||
fork: Flag.Boolean("fork").pipe(
|
||||
Flag.withDescription("Fork the session before continuing"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
model: Flag.string("model").pipe(
|
||||
model: Flag.String("model").pipe(
|
||||
Flag.withAlias("m"),
|
||||
Flag.withDescription("Model to use in the format provider/model#variant"),
|
||||
Flag.optional,
|
||||
),
|
||||
agent: Flag.string("agent").pipe(Flag.withDescription("Agent to use"), Flag.optional),
|
||||
format: Flag.choice("format", ["default", "json"]).pipe(
|
||||
agent: Flag.String("agent").pipe(Flag.withDescription("Agent to use"), Flag.optional),
|
||||
format: Flag.Literals("format", ["default", "json"]).pipe(
|
||||
Flag.withDescription("Output format"),
|
||||
Flag.withDefault("default"),
|
||||
),
|
||||
file: Flag.string("file").pipe(
|
||||
file: Flag.String("file").pipe(
|
||||
Flag.withAlias("f"),
|
||||
Flag.withDescription("File to attach to the message"),
|
||||
Flag.atMost(100),
|
||||
),
|
||||
title: Flag.string("title").pipe(Flag.withDescription("Session title"), Flag.optional),
|
||||
thinking: Flag.boolean("thinking").pipe(Flag.withDescription("Show thinking blocks"), Flag.withDefault(false)),
|
||||
title: Flag.String("title").pipe(Flag.withDescription("Session title"), Flag.optional),
|
||||
thinking: Flag.Boolean("thinking").pipe(Flag.withDescription("Show thinking blocks"), Flag.withDefault(false)),
|
||||
...PermissionParams,
|
||||
},
|
||||
}),
|
||||
@@ -400,13 +402,13 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
description: "List top-level sessions in the current project, newest first",
|
||||
params: {
|
||||
...ServerParams,
|
||||
maxCount: Flag.integer("max-count").pipe(
|
||||
maxCount: Flag.Int("max-count").pipe(
|
||||
Flag.withAlias("n"),
|
||||
Flag.withSchema(Schema.Int.check(Schema.isGreaterThanOrEqualTo(1))),
|
||||
Flag.withDescription("Limit to N most recent sessions (default: 100)"),
|
||||
Flag.optional,
|
||||
),
|
||||
format: Flag.choice("format", ["table", "json"]).pipe(
|
||||
format: Flag.Literals("format", ["table", "json"]).pipe(
|
||||
Flag.withDescription("Output format"),
|
||||
Flag.withDefault("table"),
|
||||
),
|
||||
@@ -416,18 +418,18 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
description: "Delete a session and its child sessions",
|
||||
params: {
|
||||
...ServerParams,
|
||||
sessionID: Argument.string("sessionID").pipe(Argument.withDescription("Session ID to delete")),
|
||||
sessionID: Argument.String("sessionID").pipe(Argument.withDescription("Session ID to delete")),
|
||||
},
|
||||
}),
|
||||
Spec.make("export", {
|
||||
description: "Export session data as JSON",
|
||||
params: {
|
||||
...ServerParams,
|
||||
session: Argument.string("session").pipe(
|
||||
session: Argument.String("session").pipe(
|
||||
Argument.withDescription("Session ID to export"),
|
||||
Argument.optional,
|
||||
),
|
||||
sanitize: Flag.boolean("sanitize").pipe(
|
||||
sanitize: Flag.Boolean("sanitize").pipe(
|
||||
Flag.withDescription("Redact sensitive transcript and file data"),
|
||||
Flag.withDefault(false),
|
||||
),
|
||||
@@ -437,8 +439,8 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
description: "Import session data from a JSON file or URL",
|
||||
params: {
|
||||
...ServerParams,
|
||||
file: Argument.string("file").pipe(Argument.withDescription("JSON file or URL to import")),
|
||||
directory: Flag.string("directory").pipe(
|
||||
file: Argument.String("file").pipe(Argument.withDescription("JSON file or URL to import")),
|
||||
directory: Flag.String("directory").pipe(
|
||||
Flag.withDescription("Directory in which to import the session"),
|
||||
Flag.optional,
|
||||
),
|
||||
@@ -456,8 +458,8 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("get", {
|
||||
description: "Get service configuration",
|
||||
params: {
|
||||
key: Argument.string("key").pipe(Argument.withDescription("Service setting or env"), Argument.optional),
|
||||
name: Argument.string("name").pipe(
|
||||
key: Argument.String("key").pipe(Argument.withDescription("Service setting or env"), Argument.optional),
|
||||
name: Argument.String("name").pipe(
|
||||
Argument.withDescription("Environment variable name"),
|
||||
Argument.optional,
|
||||
),
|
||||
@@ -466,11 +468,11 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("set", {
|
||||
description: "Set service configuration",
|
||||
params: {
|
||||
key: Argument.string("key").pipe(Argument.withDescription("Service setting or env")),
|
||||
value: Argument.string("value").pipe(
|
||||
key: Argument.String("key").pipe(Argument.withDescription("Service setting or env")),
|
||||
value: Argument.String("value").pipe(
|
||||
Argument.withDescription("Setting value or environment variable name"),
|
||||
),
|
||||
nestedValue: Argument.string("env-value").pipe(
|
||||
nestedValue: Argument.String("env-value").pipe(
|
||||
Argument.withDescription("Environment variable value"),
|
||||
Argument.optional,
|
||||
),
|
||||
@@ -479,8 +481,8 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("unset", {
|
||||
description: "Unset service configuration",
|
||||
params: {
|
||||
key: Argument.string("key").pipe(Argument.withDescription("Service setting or env")),
|
||||
name: Argument.string("name").pipe(
|
||||
key: Argument.String("key").pipe(Argument.withDescription("Service setting or env")),
|
||||
name: Argument.String("name").pipe(
|
||||
Argument.withDescription("Environment variable name"),
|
||||
Argument.optional,
|
||||
),
|
||||
@@ -497,7 +499,7 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("pair", {
|
||||
description: "Show server pairing information",
|
||||
params: {
|
||||
url: Flag.string("url").pipe(
|
||||
url: Flag.String("url").pipe(
|
||||
Flag.withDescription("Advertise an external HTTP(S) server URL in the pairing QR code"),
|
||||
Flag.mapTryCatch(
|
||||
(value) => {
|
||||
@@ -515,15 +517,15 @@ const Root = Spec.make(typeof OPENCODE_CLI_NAME === "string" ? OPENCODE_CLI_NAME
|
||||
Spec.make("serve", {
|
||||
description: "Start the v2 API and web server",
|
||||
params: {
|
||||
hostname: Flag.string("hostname").pipe(Flag.optional),
|
||||
port: Flag.integer("port").pipe(Flag.optional),
|
||||
cors: Flag.string("cors").pipe(
|
||||
hostname: Flag.String("hostname").pipe(Flag.optional),
|
||||
port: Flag.Int("port").pipe(Flag.optional),
|
||||
cors: Flag.String("cors").pipe(
|
||||
Flag.withSchema(Schema.NonEmptyString),
|
||||
Flag.withDescription("Additional allowed CORS origin (repeat for multiple origins)"),
|
||||
Flag.atLeast(0),
|
||||
),
|
||||
service: Flag.boolean("service").pipe(Flag.withDefault(false)),
|
||||
stdio: Flag.boolean("stdio").pipe(Flag.withDefault(false)),
|
||||
service: Flag.Boolean("service").pipe(Flag.withDefault(false)),
|
||||
stdio: Flag.Boolean("stdio").pipe(Flag.withDefault(false)),
|
||||
},
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -7,8 +7,8 @@ import { Config } from "effect"
|
||||
// The opencode server password: sent by clients connecting to an explicit
|
||||
// --server, and adopted by a manually run or standalone server. The legacy
|
||||
// name is still honored.
|
||||
export const password = Config.redacted("OPENCODE_PASSWORD").pipe(
|
||||
Config.orElse(() => Config.redacted("OPENCODE_SERVER_PASSWORD")),
|
||||
export const password = Config.Redacted("OPENCODE_PASSWORD").pipe(
|
||||
Config.orElse(() => Config.Redacted("OPENCODE_SERVER_PASSWORD")),
|
||||
Config.withDefault(undefined),
|
||||
)
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { Endpoint } from "@opencode/client/effect/service"
|
||||
import { Effect } from "effect"
|
||||
import path from "node:path"
|
||||
import { Standalone } from "../services/standalone"
|
||||
import { errorMessage } from "../util/error"
|
||||
import { reportRunError, runNonInteractiveWithOptions, type RunCommandInput } from "./run"
|
||||
|
||||
export type V1RunCommandInput = {
|
||||
@@ -54,7 +53,7 @@ export function runV1Bridge(input: V1RunCommandInput) {
|
||||
)
|
||||
}),
|
||||
),
|
||||
).catch((error) => reportRunError(input, errorMessage(error)))
|
||||
).catch((error) => reportRunError(input, error instanceof Error ? error.message : String(error)))
|
||||
}
|
||||
|
||||
function nativeInput(input: V1RunCommandInput, endpoint: Endpoint): RunCommandInput {
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Service, type Info } from "@opencode/client/effect/service"
|
||||
import path from "node:path"
|
||||
import { Effect, FileSystem, Schedule, Schema } from "effect"
|
||||
import { HttpServer } from "effect/unstable/http"
|
||||
import { NetAddress } from "effect/unstable/net"
|
||||
import { OPENCODE_VERSION } from "../version"
|
||||
|
||||
const infoJson = Schema.fromJsonString(Service.Info)
|
||||
@@ -11,7 +12,7 @@ const encodeInfo = Schema.encodeEffect(infoJson)
|
||||
const decodeInfo = Schema.decodeUnknownEffect(infoJson)
|
||||
|
||||
export const register = Effect.fnUntraced(function* (options: {
|
||||
readonly address: HttpServer.Address
|
||||
readonly address: NetAddress.SocketAddress
|
||||
readonly password: string
|
||||
readonly id: string
|
||||
readonly file: string
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { LocationGetOutput, ModelRef, OpenCodeClient, SessionInfo } from "@opencode/client/promise"
|
||||
import { Model } from "@opencode/schema/model"
|
||||
import { errorMessage } from "./util/error"
|
||||
|
||||
const SESSION_PAGE_LIMIT = 50
|
||||
|
||||
@@ -25,7 +24,7 @@ export class SessionTargetMutationError extends Error {
|
||||
override readonly name = "SessionTargetMutationError"
|
||||
|
||||
constructor(cause: unknown) {
|
||||
super(errorMessage(cause), { cause })
|
||||
super(cause instanceof Error ? cause.message : "Session target mutation failed", { cause })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,9 +125,11 @@ async function selectSession(input: {
|
||||
if (!selected) return { session: undefined, location }
|
||||
return {
|
||||
session: input.fork
|
||||
? await input.client.session.fork({ sessionID: selected.id }, ...requestOptions(input.signal)).catch((error) => {
|
||||
throw new SessionTargetMutationError(error)
|
||||
})
|
||||
? await input.client.session
|
||||
.fork({ sessionID: selected.id }, ...requestOptions(input.signal))
|
||||
.catch((error) => {
|
||||
throw new SessionTargetMutationError(error)
|
||||
})
|
||||
: selected,
|
||||
}
|
||||
}
|
||||
@@ -155,7 +156,11 @@ async function latestSession(
|
||||
return latestSession(client, location, page.cursor.next, signal)
|
||||
}
|
||||
|
||||
function resolveLocation(client: OpenCodeClient, location?: { directory?: string }, signal?: AbortSignal) {
|
||||
function resolveLocation(
|
||||
client: OpenCodeClient,
|
||||
location?: { directory?: string },
|
||||
signal?: AbortSignal,
|
||||
) {
|
||||
if (!location && !signal) return client.location.get()
|
||||
if (!location) return client.location.get(undefined, { signal })
|
||||
return client.location.get({ location }, ...requestOptions(signal))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NodeSocket } from "@effect/platform-node"
|
||||
import { Effect, Schema, Stdio, Stream } from "effect"
|
||||
import { Socket } from "effect/unstable/socket"
|
||||
|
||||
const Response = Schema.fromJsonString(Schema.Struct({ value: Schema.NullOr(Schema.String) }))
|
||||
const Port = Schema.NumberFromString.check(Schema.isInt(), Schema.isGreaterThan(0), Schema.isLessThanOrEqualTo(65535))
|
||||
@@ -10,16 +11,15 @@ export const askpass = Effect.gen(function* () {
|
||||
const port = yield* Schema.decodeUnknownEffect(Port)(process.env.OPENCODE_SSH_ASKPASS_PORT)
|
||||
const stdio = yield* Stdio.Stdio
|
||||
const socket = yield* NodeSocket.makeNet({ host: "127.0.0.1", port })
|
||||
const write = yield* socket.writer
|
||||
const writer = yield* socket.writer
|
||||
const response = { text: "" }
|
||||
yield* Effect.all(
|
||||
[
|
||||
socket.runString((text) =>
|
||||
Effect.sync(() => {
|
||||
response.text += text
|
||||
}),
|
||||
),
|
||||
write(
|
||||
Effect.gen(function* () {
|
||||
const pull = yield* Socket.readerString(socket)
|
||||
while (true) response.text += (yield* pull).join("")
|
||||
}).pipe(Effect.catchReason("SocketError", "SocketCloseError", () => Effect.void)),
|
||||
writer.write(
|
||||
JSON.stringify({
|
||||
token: process.env.OPENCODE_SSH_ASKPASS_TOKEN,
|
||||
text: process.argv.slice(2).join(" "),
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Global } from "@opencode/util/global"
|
||||
import { OPENCODE_VERSION } from "../src/version"
|
||||
import { expect, test } from "bun:test"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { NetAddress } from "effect/unstable/net"
|
||||
import fs from "node:fs/promises"
|
||||
import os from "node:os"
|
||||
import path from "node:path"
|
||||
@@ -501,7 +502,7 @@ test("service registration replaces a stale owner with the bound address", async
|
||||
try {
|
||||
const cleanup = await Effect.runPromise(
|
||||
ServiceRegistration.register({
|
||||
address: { _tag: "TcpAddress", hostname: "127.0.0.1", port: 4321 },
|
||||
address: NetAddress.inetAddressFromIpStringUnsafe("127.0.0.1", 4321),
|
||||
password: "secret",
|
||||
id: "owner",
|
||||
file: registration,
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
"@opencode/protocol": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"effect": "4.0.0-rc.112",
|
||||
"effect": "4.0.0-rc.115",
|
||||
"solid-js": ">=1.9.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
|
||||
@@ -330,8 +330,7 @@ export function make(options: ClientOptions) {
|
||||
}
|
||||
|
||||
const responseError = async (response: Response, descriptor: RequestDescriptor): Promise<never> => {
|
||||
if (descriptor.declaredStatuses.includes(response.status))
|
||||
throw declared((await json(response)) as DeclaredErrorBody)
|
||||
if (descriptor.declaredStatuses.includes(response.status)) throw await json(response)
|
||||
try {
|
||||
await response.body?.cancel()
|
||||
} catch {}
|
||||
@@ -2201,19 +2200,6 @@ async function json(response: Response): Promise<unknown> {
|
||||
}
|
||||
}
|
||||
|
||||
type DeclaredErrorBody = {
|
||||
readonly _tag?: string
|
||||
readonly message?: string
|
||||
readonly data?: { readonly message?: string }
|
||||
}
|
||||
|
||||
/** Throw declared error bodies as Errors. The body's fields stay on the error, so narrowing on `_tag` or `name` still works. */
|
||||
function declared(body: DeclaredErrorBody) {
|
||||
const error = Object.assign(new Error(body.message ?? body.data?.message), body)
|
||||
if (body._tag) error.name = body._tag
|
||||
return error
|
||||
}
|
||||
|
||||
function isContentType(response: Response, expected: string) {
|
||||
return response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() === expected
|
||||
}
|
||||
|
||||
@@ -296,7 +296,7 @@ export type ProjectIcon = { url?: string; override?: string; color?: string }
|
||||
|
||||
export type ProjectCommands = { start?: string }
|
||||
|
||||
export type ProjectTime = { created: number; updated: number; active: number }
|
||||
export type ProjectTime = { created: number; updated: number }
|
||||
|
||||
export type PermissionSource = { type: "tool"; messageID: string; id: string }
|
||||
|
||||
|
||||
@@ -1788,7 +1788,7 @@ export function createData(config: CreateDataInput) {
|
||||
},
|
||||
project: {
|
||||
list() {
|
||||
return Object.values(store.project.info).toSorted((a, b) => b.time.active - a.time.active)
|
||||
return Object.values(store.project.info).toSorted((a, b) => b.time.updated - a.time.updated)
|
||||
},
|
||||
get(projectID: string) {
|
||||
return store.project.info[projectID]
|
||||
|
||||
@@ -151,46 +151,6 @@ test("vcs.diff exposes unavailable comparisons as errors, not empty diffs", asyn
|
||||
})
|
||||
})
|
||||
|
||||
test("declared errors are thrown as Error instances that keep the body", async () => {
|
||||
const client = OpenCode.make({
|
||||
baseUrl: "http://localhost:3000",
|
||||
fetch: async () =>
|
||||
Response.json(
|
||||
{ _tag: "InvalidRequestError", message: "Incompatible auth server", kind: "integration_authorization" },
|
||||
{ status: 400 },
|
||||
),
|
||||
})
|
||||
const error = await client.integration.oauth
|
||||
.connect({ integrationID: "mcp_test", methodID: "oauth", location: { directory: "/repo" } })
|
||||
.then(
|
||||
() => undefined,
|
||||
(cause: unknown) => cause,
|
||||
)
|
||||
expect(error).toBeInstanceOf(Error)
|
||||
if (!(error instanceof Error)) throw error
|
||||
expect(error.message).toBe("Incompatible auth server")
|
||||
expect(error.name).toBe("InvalidRequestError")
|
||||
expect(error.stack).toContain("InvalidRequestError: Incompatible auth server")
|
||||
expect(error).toMatchObject({ _tag: "InvalidRequestError", kind: "integration_authorization" })
|
||||
})
|
||||
|
||||
test("declared errors with a data envelope read the nested message", async () => {
|
||||
const client = OpenCode.make({
|
||||
baseUrl: "http://localhost:3000",
|
||||
fetch: async () =>
|
||||
Response.json({ name: "WorktreeError", data: { message: "Worktree directory unavailable" } }, { status: 400 }),
|
||||
})
|
||||
const error = await client.worktree.create({ projectID: "prj_test" }).then(
|
||||
() => undefined,
|
||||
(cause: unknown) => cause,
|
||||
)
|
||||
expect(error).toBeInstanceOf(Error)
|
||||
if (!(error instanceof Error)) throw error
|
||||
expect(error.message).toBe("Worktree directory unavailable")
|
||||
expect(error.name).toBe("WorktreeError")
|
||||
expect(error).toMatchObject({ name: "WorktreeError", data: { message: "Worktree directory unavailable" } })
|
||||
})
|
||||
|
||||
test("project.update uses the global project contract", async () => {
|
||||
let request: Request | undefined
|
||||
const project = {
|
||||
|
||||
@@ -41,8 +41,8 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [x] A trailing comma after a rest parameter is a syntax error, with or without `"use strict"`.
|
||||
- [x] A program that begins with `"use strict"` rejects `yield` as an identifier and duplicate parameter names at
|
||||
parse time. Without it, `yield` is an ordinary binding.
|
||||
- [x] Duplicate parameter names in non-strict code bind the last parameter, as in JS (`function f(a, a)` called
|
||||
with `(1, 2)` sees `a === 2`).
|
||||
- [ ] Duplicate parameter names in non-strict code throw when the function is called, instead of binding the last
|
||||
parameter as JavaScript does.
|
||||
|
||||
## Values and literals
|
||||
|
||||
@@ -52,15 +52,12 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
- [x] Object literals with shorthand, computed string/number keys, and spread following ToObject: data objects and
|
||||
arrays copy own enumerable keys, strings copy index keys, and other values contribute nothing.
|
||||
- [x] Template literals with interpolation.
|
||||
- [x] Tagged templates: a tag applied to a template literal is called as `tag(strings, ...values)`, with the tag read
|
||||
like a callee so a member tag keeps its receiver. `strings` is an array of the cooked text with a read-only `raw`
|
||||
array of the source text; an invalid escape such as `\unicode` cooks to `undefined`. One template object per
|
||||
site, as in JS, but it is not frozen: `strings[0] = "x"` succeeds here where JS throws.
|
||||
- [x] Regular-expression literals.
|
||||
- [x] `NaN` and `Infinity` globals.
|
||||
- [ ] BigInt literals and in-interpreter BigInt arithmetic; BigInt remains invalid at JSON-like host boundaries.
|
||||
- [ ] Arbitrary Symbol primitive values and symbol-keyed properties. The confined `Symbol.iterator` and
|
||||
`Symbol.asyncIterator` keys are available only for the iterator protocols.
|
||||
- [ ] Tagged-template calls.
|
||||
- [ ] Getter and setter definitions in object literals.
|
||||
|
||||
## Bindings and destructuring
|
||||
@@ -89,8 +86,7 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
sources are rejected.
|
||||
- [x] Destructuring reads through the prototype chain like member access: `const { constructor } = error` and
|
||||
`const { slice } = values` find the inherited built-in.
|
||||
- [x] Any assignment target as a `for...in` head, like `for...of`: `for (x.y in obj)`, `for (a[i++] in obj)`, and
|
||||
destructuring patterns.
|
||||
- [ ] Member expressions as `for...in` targets (`for (x.y in obj)`).
|
||||
|
||||
## Statements and control flow
|
||||
|
||||
@@ -138,20 +134,11 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
arrow function.
|
||||
- [x] Promise-returning string replacers are coerced synchronously to `"[object Promise]"`, like JavaScript; they are
|
||||
not automatically awaited.
|
||||
- [x] `this` in non-arrow functions is the call's receiver: `obj.m()` and `obj["m"]()` see `obj`, a bare or detached
|
||||
call (`f()`, `const m = obj.m; m()`, `(0, obj.m)()`) sees `undefined`, as in strict JS. Arrows read the enclosing
|
||||
function's `this`. Program code has no receiver, so top-level `this` is `undefined`, as in a module.
|
||||
- [x] `arguments` in non-arrow functions: an unmapped array-like of the call's arguments (`length`, indexes, spread,
|
||||
`Array.from`), tagged `[object Arguments]` and not an Array. A parameter named `arguments` shadows it; arrows
|
||||
read the enclosing function's. `callee` and `caller` are absent rather than poisoned.
|
||||
- [x] `Function.prototype.call`, `apply`, and `bind` on program functions and built-ins:
|
||||
`Array.prototype.push.call(arr, 1)`, `Math.max.apply(null, values)`, `fn.bind(obj, first)`. `apply` accepts an
|
||||
array, an array-like object, or `null`/`undefined`. A bound function is named `bound f`, has its remaining
|
||||
`length`, and is not constructible.
|
||||
- [x] `JSON.parse` revivers and `JSON.stringify` function replacers see the holder object as `this`.
|
||||
- [ ] The optional `thisArg` of iteration methods (`map`, `forEach`, `Map.prototype.forEach`, `Array.from`, …) is
|
||||
accepted but not yet passed as `this`; callbacks run with `this` undefined.
|
||||
- [x] The optional `thisArg` of iteration methods is accepted and ignored: CodeMode functions have no `this`, so
|
||||
ignoring it matches JS arrow-function semantics exactly.
|
||||
- [ ] `this` in non-arrow CodeMode functions and callbacks.
|
||||
- [ ] User-defined constructor calls.
|
||||
- [ ] `Function.prototype.call`, `apply`, and `bind` for CodeMode functions.
|
||||
- [ ] Classes and private fields.
|
||||
- [x] Functions are objects: they hold own properties (`fn.count = 1`), enumerate them, and expose read-only `name`
|
||||
and `length`. Names follow JavaScript's NamedEvaluation: declarations, named expressions, bindings,
|
||||
@@ -184,7 +171,7 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
yielded promises; mixed async request queues; sync and async `yield*` forwarding; malformed methods/results;
|
||||
and declaration, expression, and object-method forms with closure and parameter behavior. The adapted suite
|
||||
deliberately skips Test262 variants whose observation mechanism requires unsupported getter definitions,
|
||||
proxies, prototype inspection or mutation, classes, or arbitrary symbols. It also skips tests
|
||||
proxies, prototype inspection or mutation, non-arrow `this`, classes, or arbitrary symbols. It also skips tests
|
||||
asserting exact promise reaction-turn counts beyond the observable ordering guarantee documented below. These
|
||||
are interpreter-surface boundaries, not claims that the corresponding full Test262 families pass unchanged.
|
||||
|
||||
@@ -214,18 +201,10 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
creates a hole without changing its length. Deleting a non-configurable property (`length`) or
|
||||
assigning a read-only one (`Math.PI`, `fn.name`) throws a `TypeError`, as in strict mode. `delete` of a
|
||||
non-reference (`delete 0`, `delete f()`) evaluates the operand and is `true`; `delete x` on a variable throws.
|
||||
- [x] Coercion helpers and template interpolation accept functions and namespaces: `String(fn)` and `${fn}` give
|
||||
`"[object Function]"` rather than the source text, `isNaN(fn)` is `true`.
|
||||
- [ ] Operators other than `===`/`!==`, `switch` discriminants and cases, and `Object.is` applied to a function,
|
||||
promise, generator, tool reference, or any object holding one anywhere inside; JavaScript compares by identity or
|
||||
coerces (`fn == null` is `false`, `fn + ""` is its source text), the interpreter throws
|
||||
`TypeError: Binary operators require data values.` The check walks both operands' whole object graphs, so
|
||||
`rows == null` on a large array is slow where `rows === null` is not.
|
||||
- [ ] ToPrimitive on program objects: operators, `Number`/`String`, `Error(message)`, `parseInt` radix, multi-argument
|
||||
`Date` construction and `Date.UTC`, and numeric built-in arguments (`Math.max`, `at`, `indexOf` start) should call
|
||||
the object's own `valueOf`/`toString` in spec order and surface their throws. Today they use the built-in form
|
||||
(`NaN`, `"[object Object]"`) and ignore own methods. Date setters and one-argument `Date` construction already
|
||||
follow ToPrimitive.
|
||||
- [ ] Operators, `switch` discriminants, template interpolation, and coercion helpers such as `String` and `isNaN`
|
||||
applied to functions and namespaces; JavaScript coerces them, the interpreter rejects non-data operands.
|
||||
- [ ] ToPrimitive on object operands: operators, `Error(message)`, `Date` arguments, and `parseInt` radix should call
|
||||
`valueOf`/`toString` in spec order and surface their throws.
|
||||
- [x] Property keys follow ToPropertyKey: `x[null]`, `x[true]`, and objects (via their built-in string form) become
|
||||
string keys.
|
||||
|
||||
@@ -270,7 +249,7 @@ reject }` object.
|
||||
- [x] Recursive assimilation of objects with an own callable `then` field across `Promise.resolve`, combinators,
|
||||
constructors, reactions, `finally`, `await`, and async returns. Thenable methods run deferred, receive
|
||||
first-call-wins resolve/reject functions, and ignore throws after settlement. Inherited/accessor `then` fields
|
||||
remain outside the supported object model.
|
||||
and a JavaScript `this` receiver remain outside the supported object/function model.
|
||||
- [x] Dotted tool names are canonicalized into namespace paths; a path can be both callable and a namespace, and the
|
||||
last tool supplied for a canonical path wins.
|
||||
- [x] Tool path segments may be named `constructor`, `prototype`, or `__proto__` because paths use inert Map keys.
|
||||
@@ -364,12 +343,10 @@ reject }` object.
|
||||
native JS, `split(undefined)` returns the whole string, and `includes`/`startsWith`/`endsWith` reject regular
|
||||
expressions with a native-style `TypeError`. Opaque runtime references still reject as data errors, and
|
||||
`repeat` still requires a finite non-negative count.
|
||||
- [x] Native no-argument parity for `match()`, `matchAll()`, and `search()`; all behave as an empty pattern.
|
||||
- [x] `String.raw`, on a template object or any `{ raw }` object; raw strings and substitutions coerce through their own
|
||||
`toString`.
|
||||
- [x] `match`, `matchAll`, `search`, and `split` read any non-RegExp argument as a pattern string, as `new RegExp(arg)`
|
||||
would: `"a1b".match(1)` matches `/1/`, `search(null)` looks for `"null"`, and `undefined` is the empty pattern.
|
||||
Objects use their built-in string form until ToPrimitive lands.
|
||||
- [x] Native no-argument parity for `match()`, `matchAll()`, and `search()`; all behave as an empty pattern. Present
|
||||
arguments must still be a regular expression or string pattern.
|
||||
- [ ] `String.raw`.
|
||||
- [ ] `match`, `search`, and `split` accept any value and coerce it (objects via `toString`), like JavaScript.
|
||||
|
||||
## Numbers and Math
|
||||
|
||||
@@ -401,9 +378,9 @@ reject }` object.
|
||||
- [x] `JSON.parse` and `JSON.stringify` for supported data objects.
|
||||
- [x] Numeric/string indentation for `JSON.stringify`.
|
||||
- [x] `JSON.parse` reviver callbacks, including postorder traversal, deletion through `undefined`, and root replacement.
|
||||
Revivers receive `(key, value)` with the holder as `this`.
|
||||
Revivers receive `(key, value)` but no `this` holder because CodeMode functions intentionally have no `this`.
|
||||
- [x] `JSON.stringify` function and array replacers. Function replacers receive `(key, value)` in preorder, including
|
||||
the root, with the holder as `this`. Array replacers preserve requested property order, deduplicate names, coerce
|
||||
the root, but no `this` holder. Array replacers preserve requested property order, deduplicate names, coerce
|
||||
number primitives, and ignore non-string/non-number entries. Primitive wrapper entries remain unsupported.
|
||||
- [x] Captured `console.log`, `console.info`, `console.debug`, `console.warn`, and `console.error`. An Error prints as
|
||||
`Error.prototype.toString` would show it (`Error: boom`), wherever it appears in the logged value.
|
||||
@@ -429,9 +406,8 @@ reject }` object.
|
||||
- [x] `toLocaleString`, `toLocaleDateString`, and `toLocaleTimeString` always format as `en-US` in UTC
|
||||
(`"1/1/1970, 12:00:00 AM"`) so output does not depend on the host.
|
||||
- [x] Native one-argument Date coercion for supported values, including booleans, null, arrays, and plain objects.
|
||||
- [x] Date setters and one-argument construction coerce object arguments through their own `valueOf`/`toString` and
|
||||
surface their throws.
|
||||
- [ ] Multi-argument construction and `Date.UTC` coerce object arguments the same way (see ToPrimitive above).
|
||||
- [ ] Date setters and multi-argument construction coerce object arguments through `valueOf`/`toString` and surface
|
||||
their throws.
|
||||
- [x] Native Date loose-equality and default primitive-coercion semantics, using CodeMode's deterministic ISO string
|
||||
representation for the string primitive.
|
||||
- [x] Native `RangeError` branding for invalid `toISOString()` calls.
|
||||
|
||||
@@ -24,7 +24,7 @@ import { typeofValue } from "./interpreter/references.js"
|
||||
|
||||
export type Json = Schema.Json
|
||||
|
||||
type Replacer<R> = (args: Array<Value>, holder: Obj) => Effect.Effect<Value, unknown, R>
|
||||
type Replacer<R> = (args: Array<Value>) => Effect.Effect<Value, unknown, R>
|
||||
|
||||
/**
|
||||
* What `JSON.stringify` would serialize for a program value, as host JSON: `toJSON` is honored, functions and
|
||||
@@ -60,7 +60,7 @@ const walk = <R>(
|
||||
const settled = raw instanceof PromiseObj ? yield* ctx.await(raw) : raw
|
||||
const toJSON = settled instanceof Obj ? get(settled, "toJSON") : undefined
|
||||
const own = toJSON instanceof Callable ? yield* ctx.call(toJSON, settled, [key]) : settled
|
||||
const value = replacer === undefined ? own : yield* replacer([key, own], holder)
|
||||
const value = replacer === undefined ? own : yield* replacer([key, own])
|
||||
if (value === undefined || typeofValue(value) === "function") return undefined
|
||||
if (typeof value === "number") return Number.isFinite(value) ? value : null
|
||||
if (value === null || typeof value === "string" || typeof value === "boolean") return value
|
||||
|
||||
@@ -78,7 +78,7 @@ export const applyCollectionCallback = <R>(
|
||||
ctx: Interpreter<R>,
|
||||
callback: Value,
|
||||
name: string,
|
||||
): ((args: Array<Value>, thisValue?: Value) => Effect.Effect<Value, unknown, R>) => {
|
||||
): ((args: Array<Value>) => Effect.Effect<Value, unknown, R>) => {
|
||||
if (!isSupportedCallback(callback)) {
|
||||
if (typeofValue(callback) === "function") {
|
||||
throw typeError(
|
||||
@@ -87,5 +87,5 @@ export const applyCollectionCallback = <R>(
|
||||
}
|
||||
throw typeError(`${name} expects a function callback.`)
|
||||
}
|
||||
return (callbackArgs, thisValue) => ctx.call(callback, thisValue, callbackArgs)
|
||||
return (callbackArgs) => ctx.call(callback, undefined, callbackArgs)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Effect } from "effect"
|
||||
import { Arr, Callable, coerceToInteger, coerceToString, get, Obj, type Value } from "./objects.js"
|
||||
import type { Value } from "./objects.js"
|
||||
import { arrayGlobal } from "../stdlib/array.js"
|
||||
import { textDecoderGlobal, textEncoderGlobal, uint8ArrayGlobal } from "../stdlib/bytes.js"
|
||||
import { mapGlobal, setGlobal } from "../stdlib/collections.js"
|
||||
@@ -19,7 +19,7 @@ import { base64Global, cryptoGlobal } from "../stdlib/web.js"
|
||||
import { ToolReference } from "../tool-runtime.js"
|
||||
import { errorGlobal } from "./errors.js"
|
||||
import { errorTypes } from "./intrinsics.js"
|
||||
import { constants, constructor, methods, native, receiver } from "./native.js"
|
||||
import { constants, constructor, native } from "./native.js"
|
||||
import { AsyncIteratorSymbol, IteratorSymbol, typeError } from "./model.js"
|
||||
import { generatorGlobals } from "./generators.js"
|
||||
import { promiseGlobal } from "./promises.js"
|
||||
@@ -31,25 +31,6 @@ const functionGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
Effect.sync(() => {
|
||||
throw typeError("The Function constructor is not supported; write the function inline.")
|
||||
})
|
||||
const target = (thisValue: Value, method: string) => receiver(Callable, thisValue, `Function.prototype.${method}`)
|
||||
methods(ctx.builtins, ctx.builtins.Function, [
|
||||
["call", 1, (thisValue, args) => ctx.call(target(thisValue, "call"), args[0], args.slice(1))],
|
||||
["apply", 2, (thisValue, args) => ctx.call(target(thisValue, "apply"), args[0], listFromArrayLike(args[1]))],
|
||||
[
|
||||
"bind",
|
||||
1,
|
||||
(thisValue, args) => {
|
||||
const fn = target(thisValue, "bind")
|
||||
const bound = args.slice(1)
|
||||
const length = get(fn, "length")
|
||||
return native<R>(ctx.builtins, {
|
||||
name: `bound ${coerceToString(get(fn, "name"))}`,
|
||||
length: Math.max(0, (typeof length === "number" ? length : 0) - bound.length),
|
||||
call: (_, rest) => ctx.call(fn, args[0], [...bound, ...rest]),
|
||||
})
|
||||
},
|
||||
],
|
||||
])
|
||||
return constructor<R>(ctx.builtins, ctx.builtins.Function, {
|
||||
name: "Function",
|
||||
length: 1,
|
||||
@@ -58,14 +39,6 @@ const functionGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
})
|
||||
}
|
||||
|
||||
// CreateListFromArrayLike: `apply` reads `length` and the indexed properties of any object.
|
||||
const listFromArrayLike = (value: Value): Array<Value> => {
|
||||
if (value === undefined || value === null) return []
|
||||
if (value instanceof Arr) return [...value.items]
|
||||
if (!(value instanceof Obj)) throw typeError("Function.prototype.apply expects an array-like argument list.")
|
||||
return Array.from({ length: coerceToInteger(get(value, "length")) }, (_, index) => get(value, String(index)))
|
||||
}
|
||||
|
||||
const symbolGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
const symbol = native<R>(ctx.builtins, {
|
||||
name: "Symbol",
|
||||
|
||||
@@ -32,7 +32,6 @@ import type {
|
||||
Statement,
|
||||
Super,
|
||||
SwitchStatement,
|
||||
TaggedTemplateExpression,
|
||||
Literal,
|
||||
TemplateLiteral,
|
||||
ThrowStatement,
|
||||
@@ -70,7 +69,6 @@ import {
|
||||
assign,
|
||||
Callable,
|
||||
define,
|
||||
frozen,
|
||||
get,
|
||||
hostCursor,
|
||||
IteratorObj,
|
||||
@@ -81,7 +79,6 @@ import {
|
||||
keys,
|
||||
Native,
|
||||
parseArrayIndex,
|
||||
Arguments,
|
||||
Arr,
|
||||
Fn,
|
||||
GeneratorObj,
|
||||
@@ -273,8 +270,6 @@ export class Interpreter<R> {
|
||||
readonly pending: Pending<R>
|
||||
readonly builtins: Builtins
|
||||
readonly logs: Array<string>
|
||||
/** Template objects by site: a tag sees the same `strings` array every time its literal is evaluated, as in JS. */
|
||||
readonly templates = new WeakMap<TaggedTemplateExpression, Arr>()
|
||||
private readonly root: Frame<R>
|
||||
|
||||
constructor(options: {
|
||||
@@ -288,8 +283,7 @@ export class Interpreter<R> {
|
||||
this.pending = options.pending
|
||||
this.builtins = options.builtins
|
||||
this.logs = options.logs ?? []
|
||||
// Program code has no receiver: top-level `this` is undefined, as in a module.
|
||||
const globalScope = new Map<string, Binding>([["this", { mutable: false, value: undefined }]])
|
||||
const globalScope = new Map<string, Binding>()
|
||||
// Calling back into the program never reads frame state, so any frame serves; the root is always alive.
|
||||
this.root = new Frame(this, new ScopeStack([globalScope]))
|
||||
for (const [name, value] of [...globals(this), ...(options.globals?.(this) ?? [])]) {
|
||||
@@ -470,7 +464,6 @@ class Frame<R> {
|
||||
this.scopes.capture(),
|
||||
node.async,
|
||||
node.generator,
|
||||
node.type === "ArrowFunctionExpression",
|
||||
)
|
||||
// Each generator function gets its own prototype, so `g() instanceof g` holds as in JS.
|
||||
if (node.generator)
|
||||
@@ -940,10 +933,10 @@ class Frame<R> {
|
||||
|
||||
const keys = self.enumerableKeys(right, node.right)
|
||||
|
||||
if (left.type === "RestElement" || left.type === "AssignmentPattern") {
|
||||
if (left.type !== "Identifier" && left.type !== "VariableDeclaration") {
|
||||
throw typeError("Unsupported for...in binding.", left)
|
||||
}
|
||||
const assignment = left.type === "VariableDeclaration" ? undefined : left
|
||||
const assignmentName = left.type === "Identifier" ? left.name : undefined
|
||||
|
||||
for (const key of keys) {
|
||||
const result = yield* Effect.gen(function* () {
|
||||
@@ -953,8 +946,8 @@ class Frame<R> {
|
||||
yield* self.declarePattern(declared.pattern, key, declared.mutable, left, true)
|
||||
} else if (declared) {
|
||||
yield* self.assignPattern(declared.pattern, key, left)
|
||||
} else if (assignment) {
|
||||
yield* self.assignPattern(assignment, key, left)
|
||||
} else if (assignmentName) {
|
||||
self.scopes.set(assignmentName, key, left)
|
||||
}
|
||||
return yield* self.evaluateStatement(node.body)
|
||||
}).pipe(
|
||||
@@ -1267,8 +1260,6 @@ class Frame<R> {
|
||||
}
|
||||
case "Identifier":
|
||||
return Effect.sync(() => this.scopes.get(node.name, node))
|
||||
case "ThisExpression":
|
||||
return Effect.sync(() => this.scopes.get("this", node))
|
||||
case "BinaryExpression":
|
||||
return this.evaluateBinaryExpression(node)
|
||||
case "LogicalExpression":
|
||||
@@ -1304,8 +1295,6 @@ class Frame<R> {
|
||||
return this.evaluateArrayExpression(node)
|
||||
case "TemplateLiteral":
|
||||
return this.evaluateTemplateLiteral(node)
|
||||
case "TaggedTemplateExpression":
|
||||
return this.evaluateTaggedTemplate(node)
|
||||
case "ConditionalExpression":
|
||||
return this.evaluateConditionalExpression(node)
|
||||
case "UpdateExpression":
|
||||
@@ -1622,7 +1611,7 @@ class Frame<R> {
|
||||
}
|
||||
return yield* self.createToolCallPromise(callable.path, args)
|
||||
}
|
||||
if (callable instanceof Fn) return yield* self.invokeFunction(callable, thisValue, args, node)
|
||||
if (callable instanceof Fn) return yield* self.invokeFunction(callable, args, node)
|
||||
if (callable instanceof Native) {
|
||||
return yield* self.native(() => (callable as Native<R>).call(thisValue, args), node)
|
||||
}
|
||||
@@ -1664,32 +1653,19 @@ class Frame<R> {
|
||||
}
|
||||
|
||||
// A callback invoked by a built-in runs below the call that invoked the built-in, so the deeper of the two counts.
|
||||
invokeFunction(fn: Fn, thisValue: Value, args: Array<Value>, node?: AstNode): Effect.Effect<Value, unknown, R> {
|
||||
invokeFunction(fn: Fn, args: Array<Value>, node?: AstNode): Effect.Effect<Value, unknown, R> {
|
||||
const self = this
|
||||
return Effect.flatMap(CallSite, (site) => {
|
||||
const depth = Math.max(self.depth, site.depth) + 1
|
||||
if (depth > MAX_CALL_DEPTH) throw rangeError("Maximum call stack size exceeded", node)
|
||||
const invocation = new Frame(this.ctx, new ScopeStack([...fn.capturedScopes, new Map()]), depth)
|
||||
const paramScope = invocation.scopes.current()
|
||||
// `this` and `arguments` are scope bindings so arrows resolve them lexically; a parameter named
|
||||
// `arguments` shadows the object, as in JS.
|
||||
if (!fn.arrow) {
|
||||
paramScope.set("this", { mutable: false, value: thisValue, initialized: true })
|
||||
paramScope.set("arguments", {
|
||||
mutable: true,
|
||||
value: new Arguments(self.ctx.builtins.Object, [...args]),
|
||||
initialized: true,
|
||||
})
|
||||
}
|
||||
// Seed all parameters first so defaults cannot fall through to same-named outer bindings.
|
||||
const paramScope = invocation.scopes.current()
|
||||
for (const parameter of fn.parameters) {
|
||||
for (const name of collectPatternNames(parameter)) {
|
||||
paramScope.set(name, { mutable: true, value: undefined, initialized: false })
|
||||
}
|
||||
}
|
||||
const parameters = fn.parameters.map((parameter) =>
|
||||
parameter.type === "Identifier" ? parameter.name : undefined,
|
||||
)
|
||||
const bind = Effect.gen(function* () {
|
||||
for (const [index, parameter] of fn.parameters.entries()) {
|
||||
if (parameter.type === "RestElement") {
|
||||
@@ -1702,8 +1678,6 @@ class Frame<R> {
|
||||
)
|
||||
break
|
||||
}
|
||||
// A sloppy simple parameter list may repeat a name; the last occurrence wins, as in JS.
|
||||
if (parameter.type === "Identifier" && parameters.lastIndexOf(parameter.name) !== index) continue
|
||||
yield* invocation.declarePattern(parameter, args[index], true, parameter, true)
|
||||
}
|
||||
})
|
||||
@@ -2032,7 +2006,7 @@ class Frame<R> {
|
||||
return Effect.gen(function* () {
|
||||
for (let index = 0; index < quasis.length; index += 1) {
|
||||
const quasi = quasis[index]!
|
||||
// acorn only omits `cooked` for invalid escapes, which are a parse error outside a tagged template.
|
||||
// acorn only omits `cooked` for invalid escapes in tagged templates, which are unsupported.
|
||||
if (typeof quasi.value.cooked !== "string") {
|
||||
throw typeError("Invalid template literal quasi.", quasi)
|
||||
}
|
||||
@@ -2050,41 +2024,6 @@ class Frame<R> {
|
||||
})
|
||||
}
|
||||
|
||||
// `tag\`a${x}b\`` is `tag(strings, x)`: the tag is read like a callee (a member keeps its receiver), the
|
||||
// substitutions are evaluated in order, and `strings` carries the escaped source as `strings.raw`.
|
||||
private evaluateTaggedTemplate(node: TaggedTemplateExpression): Effect.Effect<Value, unknown, R> {
|
||||
const self = this
|
||||
return Effect.gen(function* () {
|
||||
const { callable, thisValue } =
|
||||
node.tag.type === "MemberExpression"
|
||||
? yield* self.readMethod(node.tag)
|
||||
: { callable: yield* self.evaluateExpression(node.tag), thisValue: undefined }
|
||||
const strings = self.ctx.templates.get(node) ?? self.createTemplateObject(node)
|
||||
const values = yield* Effect.forEach(node.quasi.expressions, (expression) => self.evaluateExpression(expression))
|
||||
return yield* self.call(callable, thisValue, [strings, ...values], node, node.tag)
|
||||
})
|
||||
}
|
||||
|
||||
private createTemplateObject(node: TaggedTemplateExpression): Arr {
|
||||
const array = this.ctx.builtins.Array
|
||||
// An invalid escape such as `\unicode` cooks to `undefined` and survives only in `raw`.
|
||||
const strings = new Arr(
|
||||
array,
|
||||
node.quasi.quasis.map((quasi) => quasi.value.cooked ?? undefined),
|
||||
)
|
||||
define(
|
||||
strings,
|
||||
"raw",
|
||||
new Arr(
|
||||
array,
|
||||
node.quasi.quasis.map((quasi) => quasi.value.raw),
|
||||
),
|
||||
frozen,
|
||||
)
|
||||
this.ctx.templates.set(node, strings)
|
||||
return strings
|
||||
}
|
||||
|
||||
private evaluateConditionalExpression(node: ConditionalExpression): Effect.Effect<Value, unknown, R> {
|
||||
return Effect.flatMap(this.evaluateExpression(node.test), (test) =>
|
||||
this.evaluateExpression(test ? node.consequent : node.alternate),
|
||||
|
||||
@@ -72,7 +72,7 @@ export const uriError = failure("URIError")
|
||||
|
||||
// Orient the agent rather than enumerate JavaScript; interpreter-support.md is the full matrix.
|
||||
export const supportedSyntaxMessage =
|
||||
"This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, getters/setters, BigInt, and custom Symbols. Use plain functions and data objects instead."
|
||||
"This is a restricted JavaScript-like language. Supported: plain and async functions, data literals, destructuring, standard control flow, await and Promise, and built-ins such as Array, Object, Math, JSON, Date, RegExp, Map, Set, and URL. Unsupported: classes, this, getters/setters, tagged templates, BigInt, and custom Symbols. Use plain functions and data objects instead."
|
||||
|
||||
export const unsupportedSyntax = (kind: string, node: AstNode): PendingThrow =>
|
||||
new PendingThrow(
|
||||
|
||||
@@ -90,7 +90,7 @@ export class Obj {
|
||||
}
|
||||
|
||||
export class Arr extends Obj {
|
||||
override readonly tag: string = "Array"
|
||||
override readonly tag = "Array"
|
||||
constructor(
|
||||
proto: Obj,
|
||||
readonly items: Array<Value> = [],
|
||||
@@ -162,19 +162,12 @@ export class Fn extends Callable {
|
||||
readonly capturedScopes: Array<Map<string, Binding>>,
|
||||
readonly async: boolean,
|
||||
readonly generator: boolean,
|
||||
/** Arrows have no `this` or `arguments` of their own; they read the enclosing function's. */
|
||||
readonly arrow: boolean,
|
||||
) {
|
||||
const optional = parameters.findIndex((p) => p.type === "AssignmentPattern" || p.type === "RestElement")
|
||||
super(proto, name, optional === -1 ? parameters.length : optional)
|
||||
}
|
||||
}
|
||||
|
||||
/** The strict `arguments` object: an unmapped copy of the call's arguments that is not an Array. */
|
||||
export class Arguments extends Arr {
|
||||
override readonly tag = "Arguments"
|
||||
}
|
||||
|
||||
export type NativeCall<R> = (thisValue: Value, args: Array<Value>) => Effect.Effect<Value, unknown, R>
|
||||
export type NativeConstruct<R> = (args: Array<Value>, newTarget: Callable) => Effect.Effect<Value, unknown, R>
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
define,
|
||||
get,
|
||||
hidden,
|
||||
Arguments,
|
||||
Arr,
|
||||
GeneratorObj,
|
||||
hostIterator,
|
||||
@@ -119,7 +118,7 @@ export const arrayGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
construct: (args, newTarget) => Effect.sync(() => construct(args, prototypeFrom(newTarget, proto))),
|
||||
})
|
||||
methods(builtins, array, [
|
||||
["isArray", 1, (_, args) => args[0] instanceof Arr && !(args[0] instanceof Arguments)],
|
||||
["isArray", 1, (_, args) => args[0] instanceof Arr],
|
||||
["of", 0, (_, args) => wrap([...args])],
|
||||
["from", 1, (_, args) => arrayFrom(ctx, args)],
|
||||
])
|
||||
|
||||
@@ -40,7 +40,7 @@ const parse = <R>(ctx: Interpreter<R>, args: Array<Value>): Effect.Effect<Value,
|
||||
else set(value, name, revived)
|
||||
}
|
||||
}
|
||||
return yield* apply([key, value], holder)
|
||||
return yield* apply([key, value])
|
||||
})
|
||||
return visit(record(ctx.builtins.Object, { "": parsed }), "")
|
||||
}
|
||||
|
||||
@@ -33,16 +33,21 @@ const escapeRegexHint =
|
||||
'To match special characters like ( ) [ ] { } + * ? . literally, escape them with a backslash (e.g. "\\\\(") or test for them with String.includes instead.'
|
||||
|
||||
export const toHostRegex = (arg: Value, method: string, extraFlags = ""): RegExp => {
|
||||
// Native parity: an undefined pattern behaves as an empty pattern.
|
||||
if (arg === undefined) return new RegExp("", extraFlags)
|
||||
if (arg instanceof RegExpObj) return arg.regex
|
||||
// Anything else is a pattern string, as `new RegExp(arg)` would read it: undefined is the empty pattern.
|
||||
const source = arg === undefined ? "" : coerceToString(arg)
|
||||
try {
|
||||
return new RegExp(source, extraFlags)
|
||||
} catch (error) {
|
||||
throw syntaxError(
|
||||
`String.${method} received the string ${JSON.stringify(source)}, which is not a valid regular expression pattern (${regexFailureReason(error)}). ${escapeRegexHint}`,
|
||||
)
|
||||
if (typeof arg === "string") {
|
||||
try {
|
||||
return new RegExp(arg, extraFlags)
|
||||
} catch (error) {
|
||||
throw syntaxError(
|
||||
`String.${method} received the string ${JSON.stringify(arg)}, which is not a valid regular expression pattern (${regexFailureReason(error)}). ${escapeRegexHint}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
throw typeError(
|
||||
`String.${method} expects a regular expression (a /pattern/flags literal or new RegExp(...)) or a string pattern, not ${arg === null ? "null" : typeof arg}.`,
|
||||
)
|
||||
}
|
||||
|
||||
export const matchToValue = (builtins: Builtins, match: RegExpMatchArray): Arr => {
|
||||
|
||||
@@ -4,20 +4,17 @@ import { checkArrayLength, checkStringLength } from "../interpreter/limits.js"
|
||||
import { invalidData, IteratorSymbol, rangeError, typeError } from "../interpreter/model.js"
|
||||
import {
|
||||
define,
|
||||
get,
|
||||
hidden,
|
||||
Arr,
|
||||
hostIterator,
|
||||
Obj,
|
||||
RegExpObj,
|
||||
record,
|
||||
coerceToInteger,
|
||||
coerceToNumber,
|
||||
coerceToString,
|
||||
type Value,
|
||||
} from "../interpreter/objects.js"
|
||||
import { containsOpaqueReference, typeofValue } from "../interpreter/references.js"
|
||||
import { applyCollectionCallback, isSupportedCallback, toPrimitiveString } from "../interpreter/callback.js"
|
||||
import { applyCollectionCallback, isSupportedCallback } from "../interpreter/callback.js"
|
||||
import type { Interpreter } from "../interpreter/interpreter.js"
|
||||
import { matchToValue, toHostRegex } from "./regexp.js"
|
||||
import { coercion } from "./value.js"
|
||||
@@ -101,29 +98,6 @@ export const stringGlobal = <R>(ctx: Interpreter<R>) => {
|
||||
methods(builtins, string, [
|
||||
codeUnits("fromCharCode", String.fromCharCode),
|
||||
codeUnits("fromCodePoint", String.fromCodePoint),
|
||||
[
|
||||
"raw",
|
||||
1,
|
||||
(_, args) => {
|
||||
const template = args[0]
|
||||
const raw = template instanceof Obj ? get(template, "raw") : undefined
|
||||
if (!(raw instanceof Obj)) throw typeError("String.raw expects a template object with a raw array.")
|
||||
const count = Math.max(0, coerceToInteger(get(raw, "length")))
|
||||
checkArrayLength(count)
|
||||
// Each literal is followed by its substitution, except the last literal, or when substitutions run out.
|
||||
const parts = Array.from({ length: count }, (_, index) =>
|
||||
index + 1 < count && index + 1 < args.length ? [get(raw, index), args[index + 1]] : [get(raw, index)],
|
||||
).flat()
|
||||
return Effect.map(
|
||||
Effect.forEach(parts, (part) => toPrimitiveString(ctx, part)),
|
||||
(strings) => {
|
||||
const output = strings.join("")
|
||||
checkStringLength(output.length)
|
||||
return output
|
||||
},
|
||||
)
|
||||
},
|
||||
],
|
||||
])
|
||||
|
||||
const self = (thisValue: Value, name: string): string => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { JsonPointer, Schema } from "effect"
|
||||
import { JsonPointer, Schema, SchemaAST } from "effect"
|
||||
import type { Tool, JsonSchema, SchemaType } from "./tool.js"
|
||||
|
||||
const isEffectSchema = (schema: SchemaType): schema is Schema.Decoder<unknown> & Schema.Top => Schema.isSchema(schema)
|
||||
@@ -12,8 +12,14 @@ const renderKey = (name: string): string => (identifierSegment.test(name) ? name
|
||||
const effectNumberSentinel = (schema: JsonSchema) =>
|
||||
schema.type === "string" &&
|
||||
Array.isArray(schema.enum) &&
|
||||
schema.enum.length === 1 &&
|
||||
(schema.enum[0] === "NaN" || schema.enum[0] === "Infinity" || schema.enum[0] === "-Infinity")
|
||||
(schema.enum.length === 1 ||
|
||||
(schema.enum.length === 3 && ["NaN", "Infinity", "-Infinity"].every((value) => schema.enum?.includes(value)))) &&
|
||||
schema.enum.every((value) => value === "NaN" || value === "Infinity" || value === "-Infinity")
|
||||
|
||||
const definitionName = (ref: string): string | undefined => {
|
||||
const tokens = JsonPointer.parseUriFragment(ref)
|
||||
return tokens?.length === 2 && (tokens[0] === "$defs" || tokens[0] === "definitions") ? tokens[1] : undefined
|
||||
}
|
||||
|
||||
const intersection = (members: ReadonlyArray<string>): string => {
|
||||
const concrete = members.filter((member) => member !== "unknown")
|
||||
@@ -38,8 +44,7 @@ const hasUnresolvedRef = (
|
||||
if (visited.has(schema)) return false
|
||||
const nextVisited = new Set([...visited, schema])
|
||||
if (schema.$ref !== undefined) {
|
||||
const segment = schema.$ref.match(/^#\/(?:\$defs|definitions)\/([^/]+)$/)?.[1]
|
||||
const name = segment === undefined ? undefined : JsonPointer.unescapeToken(segment)
|
||||
const name = definitionName(schema.$ref)
|
||||
if (name === undefined || definitions[name] === undefined || seen.has(name)) return true
|
||||
if (hasUnresolvedRef(definitions[name], definitions, new Set([...seen, name]), nextVisited)) return true
|
||||
}
|
||||
@@ -130,8 +135,7 @@ const renderSchema = (
|
||||
? ctx
|
||||
: { ...ctx, definitions: { ...ctx.definitions, ...(schema.definitions ?? {}), ...(schema.$defs ?? {}) } }
|
||||
if (schema.$ref) {
|
||||
const segment = schema.$ref.match(/^#\/(?:\$defs|definitions)\/([^/]+)$/)?.[1]
|
||||
const name = segment === undefined ? undefined : JsonPointer.unescapeToken(segment)
|
||||
const name = definitionName(schema.$ref)
|
||||
if (!name || !nested.definitions[name] || seen.has(name)) return "unknown"
|
||||
return intersection([
|
||||
renderSchema(nested.definitions[name], nested, depth, new Set([...seen, name])),
|
||||
@@ -203,7 +207,7 @@ const renderSchema = (
|
||||
export const toTypeScript = (schema: Schema.Top, decoded = false, pretty = false): string => {
|
||||
try {
|
||||
const visible = decoded ? Schema.toType(schema) : schema
|
||||
const document = Schema.toJsonSchemaDocument(visible) as {
|
||||
const document = Schema.toJsonSchemaDocument(visible, { onExcessProperty: "error" }) as {
|
||||
readonly schema: JsonSchema
|
||||
readonly definitions?: Readonly<Record<string, JsonSchema>>
|
||||
}
|
||||
@@ -230,7 +234,7 @@ export type InputProperty = {
|
||||
export const inputProperties = <R>(tool: Tool<R>): Array<InputProperty> => {
|
||||
try {
|
||||
const document = isEffectSchema(tool.input)
|
||||
? (Schema.toJsonSchemaDocument(tool.input) as {
|
||||
? (Schema.toJsonSchemaDocument(tool.input, { onExcessProperty: "error" }) as {
|
||||
readonly schema: JsonSchema
|
||||
readonly definitions?: Readonly<Record<string, JsonSchema>>
|
||||
})
|
||||
@@ -241,8 +245,7 @@ export const inputProperties = <R>(tool: Tool<R>): Array<InputProperty> => {
|
||||
const definitions = document.definitions ?? {}
|
||||
let schema = document.schema
|
||||
if (schema.$ref !== undefined) {
|
||||
const segment = schema.$ref.match(/^#\/(?:\$defs|definitions)\/([^/]+)$/)?.[1]
|
||||
const name = segment === undefined ? undefined : JsonPointer.unescapeToken(segment)
|
||||
const name = definitionName(schema.$ref)
|
||||
const resolved = name === undefined ? undefined : definitions[name]
|
||||
if (resolved === undefined) return []
|
||||
schema = resolved
|
||||
@@ -261,10 +264,16 @@ export const inputProperties = <R>(tool: Tool<R>): Array<InputProperty> => {
|
||||
export const inputTypeScript = <R>(tool: Tool<R>, pretty = false): string =>
|
||||
isEffectSchema(tool.input) ? toTypeScript(tool.input, false, pretty) : jsonSchemaToTypeScript(tool.input, pretty)
|
||||
|
||||
// Empty object schemas render as `{}` in compact form; anything with properties,
|
||||
// an index signature, or union members renders differently, so equality is a
|
||||
// conservative emptiness test for both Effect and JSON Schema inputs.
|
||||
export const isEmptyInput = <R>(tool: Tool<R>): boolean => inputTypeScript(tool) === "{}"
|
||||
// Effect 4.0 models an empty Struct as a non-nullish object, so inspect its AST.
|
||||
// Raw JSON Schema inputs retain the compact `{}` rendering check.
|
||||
export const isEmptyInput = <R>(tool: Tool<R>): boolean => {
|
||||
if (!isEffectSchema(tool.input)) return inputTypeScript(tool) === "{}"
|
||||
return (
|
||||
SchemaAST.isObjects(tool.input.ast) &&
|
||||
tool.input.ast.propertySignatures.length === 0 &&
|
||||
tool.input.ast.indexSignatures.length === 0
|
||||
)
|
||||
}
|
||||
|
||||
export const outputTypeScript = <R>(tool: Tool<R>, pretty = false): string =>
|
||||
tool.output === undefined
|
||||
|
||||
@@ -210,14 +210,11 @@ describe("Test262 JSON.stringify replacer adaptations", () => {
|
||||
})
|
||||
|
||||
describe("CodeMode JSON callback boundaries", () => {
|
||||
test("revivers and replacers see the holder as this", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const revived = JSON.parse('{"a":{"b":1}}', function (key, item) { return key === "b" ? this.b + 1 : item })
|
||||
const text = JSON.stringify({ a: 1, b: 2 }, function (key, item) { return key === "a" ? this.b : item })
|
||||
return [revived, text]
|
||||
`),
|
||||
).toEqual([{ a: { b: 2 } }, '{"a":2,"b":2}'])
|
||||
test("this remains unsupported rather than exposing callback holders", async () => {
|
||||
const result = await Effect.runPromise(
|
||||
CodeMode.execute({ code: `return JSON.parse("1", function (key, item) { return this })`, tools: {} }),
|
||||
)
|
||||
expect(result).toMatchObject({ ok: false, error: { kind: "UnsupportedSyntax" } })
|
||||
})
|
||||
|
||||
test("prototype-named keys parse as own data and reach the reviver", async () => {
|
||||
|
||||
@@ -77,6 +77,8 @@ describe("new on a non-constructible callee", () => {
|
||||
expect(failure.message).toStartWith(
|
||||
"SyntaxError: Syntax 'ClassDeclaration' is not supported. This is a restricted JavaScript-like language. Supported: ",
|
||||
)
|
||||
expect(failure.message).toContain("Unsupported: classes, getters/setters, BigInt, and custom Symbols.")
|
||||
expect(failure.message).toContain(
|
||||
"Unsupported: classes, this, getters/setters, tagged templates, BigInt, and custom Symbols.",
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -964,7 +964,7 @@ describe("coercion parity: unknown static members read as undefined", () => {
|
||||
expect(await value(`return typeof Math.sum`)).toBe("undefined")
|
||||
expect(await value(`return RegExp.quote === undefined`)).toBe(true)
|
||||
expect(await value(`return Number.range === undefined`)).toBe(true)
|
||||
expect(await value(`return String.dedent === undefined`)).toBe(true)
|
||||
expect(await value(`return String.raw === undefined`)).toBe(true)
|
||||
expect(await value(`return isFinite.something === undefined`)).toBe(true)
|
||||
expect(await value(`return console.group === undefined`)).toBe(true)
|
||||
expect(await value(`return Date.moment === undefined`)).toBe(true)
|
||||
@@ -1079,190 +1079,3 @@ describe("functions are objects", () => {
|
||||
).toEqual([3, ["count"], true, true, "fn", 3, true, true, null])
|
||||
})
|
||||
})
|
||||
|
||||
describe("tagged templates", () => {
|
||||
test("the tag receives the cooked strings, their raw forms, and the substitutions in order", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const tag = (strings, ...values) => [strings, strings.raw, values, Object.keys(strings)]
|
||||
return tag\`a\${1}b\\n\${2}c\`
|
||||
`),
|
||||
).toEqual([
|
||||
["a", "b\n", "c"],
|
||||
["a", "b\\n", "c"],
|
||||
[1, 2],
|
||||
["0", "1", "2"],
|
||||
])
|
||||
})
|
||||
|
||||
test("an invalid escape cooks to undefined and keeps its raw text", async () => {
|
||||
expect(await value(`return ((strings) => [strings[0] === undefined, strings.raw[0]])\`\\unicode\``)).toEqual([
|
||||
true,
|
||||
"\\unicode",
|
||||
])
|
||||
})
|
||||
|
||||
test("each site has one template object; different sites differ", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const seen = []
|
||||
const tag = (strings) => { seen.push(strings) }
|
||||
for (let i = 0; i < 2; i++) tag\`x\${i}\`
|
||||
tag\`x\${0}\`
|
||||
return [seen[0] === seen[1], seen[0] === seen[2]]
|
||||
`),
|
||||
).toEqual([true, false])
|
||||
})
|
||||
|
||||
test("the tag is read like a callee: members, chained tags, async tags, and the not-a-function error", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const o = { tag: (strings) => strings[0].toUpperCase() }
|
||||
const chain = () => chain
|
||||
const asyncTag = async (strings, value) => strings[0] + value
|
||||
let failure
|
||||
try { (1)\`x\` } catch (error) { failure = error instanceof TypeError }
|
||||
return [o.tag\`abc\`, typeof chain\`a\`\`b\`, await asyncTag\`n=\${1}\`, failure]
|
||||
`),
|
||||
).toEqual(["ABC", "function", "n=1", true])
|
||||
})
|
||||
|
||||
test("raw is read-only", async () => {
|
||||
expect(await value(`try { ((strings) => { strings.raw = 1 })\`a\` } catch (error) { return error.name }`)).toBe(
|
||||
"TypeError",
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("String.raw", () => {
|
||||
test("joins the raw strings with the substitutions", async () => {
|
||||
expect(await value(`return [String.raw\`a\\n\${1}b\`, String.raw({ raw: ["x", "y", "z"] }, 1, 2, 3)]`)).toEqual([
|
||||
"a\\n1b",
|
||||
"x1y2z",
|
||||
])
|
||||
})
|
||||
|
||||
test("extra substitutions are dropped, missing ones are skipped, and a program object's toString is used", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const shout = { toString() { return "!" } }
|
||||
return [String.raw({ raw: ["x", "y"] }, 1, 2), String.raw({ raw: ["x", "y", "z"] }, shout), String.raw({ raw: { length: 0 } })]
|
||||
`),
|
||||
).toEqual(["x1y", "x!yz", ""])
|
||||
})
|
||||
|
||||
test("a template without a raw array is a TypeError", async () => {
|
||||
const failure = await error(`String.raw(1)`)
|
||||
expect(failure.message).toContain("String.raw expects a template object with a raw array")
|
||||
})
|
||||
})
|
||||
|
||||
describe("sloppy duplicate parameters and for...in targets", () => {
|
||||
test("a repeated parameter name binds the last argument", async () => {
|
||||
expect(await value(`function f(a, b, a) { return [a, b] } return [f(1, 2, 3), f(1)]`)).toEqual([
|
||||
[3, 2],
|
||||
[null, null],
|
||||
])
|
||||
})
|
||||
|
||||
test("for...in assigns to any target: members, computed members, and patterns", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const x = {}, seen = [], a = []
|
||||
let i = 0, first
|
||||
for (x.y in { p: 1, q: 2 }) seen.push(x.y)
|
||||
for (a[i++] in { p: 1, q: 2 });
|
||||
for ([first] in { ab: 1 });
|
||||
return [seen, x.y, a, first]
|
||||
`),
|
||||
).toEqual([["p", "q"], "q", ["p", "q"], "a"])
|
||||
})
|
||||
})
|
||||
|
||||
describe("this, arguments, and Function.prototype.call/apply/bind", () => {
|
||||
test("this is the call receiver for non-arrow functions and lexical for arrows", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const o = { n: 1, m() { return this.n }, a() { return (() => this.n)() }, bare() { return this } }
|
||||
const detached = o.bare
|
||||
function f() { return this }
|
||||
return [o.m(), o["m"](), o?.m(), (o.m)(), o.a(), o.bare() === o, detached(), f(), (0, o.bare)(), this, (() => this)()]
|
||||
`),
|
||||
).toEqual([1, 1, 1, 1, 1, true, null, null, null, null, null])
|
||||
})
|
||||
|
||||
test("this reaches generator and async methods and plain-function callbacks", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const o = { n: 2, *g() { yield this.n }, async m() { return this.n }, xs: [1, 2], go() { return this.xs.map(function (x) { return [x, this] }) } }
|
||||
return [[...o.g()], await o.m(), o.go()]
|
||||
`),
|
||||
).toEqual([
|
||||
[2],
|
||||
2,
|
||||
[
|
||||
[1, null],
|
||||
[2, null],
|
||||
],
|
||||
])
|
||||
})
|
||||
|
||||
test("arguments is an unmapped array-like that arrows and parameters interact with as in JS", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
function f(a) { arguments[0] = 9; return [arguments.length, arguments[1], a, [...arguments], Array.isArray(arguments), Object.prototype.toString.call(arguments), typeof arguments.map, (() => arguments[1])()] }
|
||||
function shadow(arguments) { return arguments }
|
||||
function hoisted() { var arguments; return arguments.length }
|
||||
let outer
|
||||
try { outer = arguments } catch (error) { outer = error.name }
|
||||
return [f(1, 2), shadow(7), hoisted(1, 2, 3), outer]
|
||||
`),
|
||||
).toEqual([[2, 2, 1, [9, 2], false, "[object Arguments]", "undefined", 2], 7, 3, "ReferenceError"])
|
||||
})
|
||||
|
||||
test("call, apply, and bind set this and arguments on program functions and built-ins", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
function f(a, b, c) { return [this, a, b, c] }
|
||||
const g = f.bind({ k: 1 }, "A")
|
||||
const arr = [1]
|
||||
Array.prototype.push.call(arr, 2, 3)
|
||||
return [
|
||||
f.call("t", 1, 2),
|
||||
f.apply({ k: 2 }, [1, 2]),
|
||||
f.apply(null, { length: 2, 0: "x", 1: "y" }),
|
||||
f.apply(null).length,
|
||||
g("B", "C"), g.name, g.length,
|
||||
f.bind(1).bind(2)()[0],
|
||||
arr,
|
||||
Math.max.apply(null, [1, 5, 3]),
|
||||
Math.max.bind(null, 10)(3),
|
||||
[1, 2].map(f.bind(null, 0)).map((r) => r[1]),
|
||||
]
|
||||
`),
|
||||
).toEqual([
|
||||
["t", 1, 2, null],
|
||||
[{ k: 2 }, 1, 2, null],
|
||||
[null, "x", "y", null],
|
||||
4,
|
||||
[{ k: 1 }, "A", "B", "C"],
|
||||
"bound f",
|
||||
2,
|
||||
1,
|
||||
[1, 2, 3],
|
||||
5,
|
||||
10,
|
||||
[0, 0],
|
||||
])
|
||||
})
|
||||
|
||||
test("call and apply reject non-callable receivers and non-array-like argument lists", async () => {
|
||||
expect((await error(`Function.prototype.call.call(1)`)).message).toContain(
|
||||
"Function.prototype.call called on incompatible receiver",
|
||||
)
|
||||
expect((await error(`(() => 1).apply(null, 5)`)).message).toContain("expects an array-like argument list")
|
||||
expect((await error(`function f(n) { return f.call(null, n + 1) } f(0)`)).message).toContain(
|
||||
"Maximum call stack size exceeded",
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Effect, Schema } from "effect"
|
||||
import { CodeMode, Tool } from "../src/index.js"
|
||||
import { inputTypeScript, jsonSchemaToTypeScript, outputTypeScript } from "../src/tool-schema.js"
|
||||
import {
|
||||
decodeInput,
|
||||
inputProperties,
|
||||
inputTypeScript,
|
||||
jsonSchemaToTypeScript,
|
||||
outputTypeScript,
|
||||
} from "../src/tool-schema.js"
|
||||
|
||||
// A raw JSON Schema tool in the shape an MCP adapter produces: render-only input schema
|
||||
// whose property descriptions and constraints must surface as JSDoc in pretty signatures.
|
||||
@@ -525,6 +531,34 @@ describe("pretty signature rendering", () => {
|
||||
})
|
||||
|
||||
describe("JSON Schema definition scope", () => {
|
||||
test.each(["Lookup Input", "café", "A/B~C% D#E"])(
|
||||
"resolves Effect definition %s in signatures and input metadata",
|
||||
(identifier) => {
|
||||
const tool = Tool.make({
|
||||
description: "Named tool",
|
||||
input: Schema.Struct({ city: Schema.String }).annotate({ identifier }),
|
||||
output: Schema.Struct({ city: Schema.String }).annotate({ identifier }),
|
||||
execute: (input) => Effect.succeed(input),
|
||||
})
|
||||
expect(inputTypeScript(tool)).toBe("{ city: string }")
|
||||
expect(outputTypeScript(tool)).toBe("{ city: string }")
|
||||
expect(inputProperties(tool)).toEqual([{ name: "city", description: undefined, required: true }])
|
||||
},
|
||||
)
|
||||
|
||||
test.each(["#/$defs/%", "#/$defs/A~2B", "#/$defs/Missing", "#/$defs/Loop", "https://example.test/schema"])(
|
||||
"keeps malformed, unresolved, and recursive reference %s unknown",
|
||||
($ref) => {
|
||||
const tool = Tool.make({
|
||||
description: "Unresolved tool",
|
||||
input: { $ref, $defs: { Loop: { $ref: "#/$defs/Loop" } } },
|
||||
execute: () => Effect.succeed(null),
|
||||
})
|
||||
expect(inputTypeScript(tool)).toBe("unknown")
|
||||
expect(inputProperties(tool)).toEqual([])
|
||||
},
|
||||
)
|
||||
|
||||
test.each(["definitions", "$defs"])("resolves root %s and lets $defs take precedence", (key) => {
|
||||
const schema = { $ref: `#/${key}/Value`, [key]: { Value: { type: "string" } } }
|
||||
expect(jsonSchemaToTypeScript(schema)).toBe("string")
|
||||
@@ -612,14 +646,51 @@ describe("non-identifier property names render as quoted keys", () => {
|
||||
input: Schema.Struct({ "foo-bar": Schema.String, plain: Schema.optionalKey(Schema.Number) }),
|
||||
execute: () => Effect.succeed(null),
|
||||
})
|
||||
expect(inputTypeScript(tool)).toBe('{ "foo-bar": string; plain?: number | "Infinity" | "-Infinity" | "NaN" }')
|
||||
expect(inputTypeScript(tool, true)).toBe(
|
||||
["{", ' "foo-bar": string,', ' plain?: number | "Infinity" | "-Infinity" | "NaN",', "}"].join("\n"),
|
||||
)
|
||||
expect(inputTypeScript(tool)).toBe('{ "foo-bar": string; plain?: number }')
|
||||
expect(inputTypeScript(tool, true)).toBe(["{", ' "foo-bar": string,', " plain?: number,", "}"].join("\n"))
|
||||
})
|
||||
})
|
||||
|
||||
describe("union schemas render every alternative", () => {
|
||||
test("Effect numbers advertise the numeric values accepted by the input decoder", () => {
|
||||
const tool = Tool.make({
|
||||
description: "Numeric tool",
|
||||
input: Schema.Struct({ amount: Schema.Number }),
|
||||
output: Schema.Number,
|
||||
execute: (input) => Effect.succeed(input.amount),
|
||||
})
|
||||
expect(inputTypeScript(tool)).toBe("{ amount: number }")
|
||||
expect(inputTypeScript(tool, true)).toBe("{\n amount: number,\n}")
|
||||
expect(outputTypeScript(tool)).toBe("number")
|
||||
expect(outputTypeScript(tool, true)).toBe("number")
|
||||
expect(decodeInput(tool, { amount: 42 })).toEqual({ amount: 42 })
|
||||
for (const amount of ["NaN", "Infinity", "-Infinity"]) {
|
||||
expect(() => decodeInput(tool, { amount })).toThrow("Expected number")
|
||||
}
|
||||
})
|
||||
|
||||
test("keeps unrelated and partial grouped string enums alongside numbers", () => {
|
||||
expect(
|
||||
jsonSchemaToTypeScript({
|
||||
anyOf: [{ type: "number" }, { type: "string", enum: ["NaN", "Infinity", "unknown"] }],
|
||||
}),
|
||||
).toBe('number | "NaN" | "Infinity" | "unknown"')
|
||||
expect(
|
||||
jsonSchemaToTypeScript({
|
||||
anyOf: [{ type: "number" }, { type: "string", enum: ["NaN", "Infinity"] }],
|
||||
}),
|
||||
).toBe('number | "NaN" | "Infinity"')
|
||||
const tool = Tool.make({
|
||||
description: "Number or status",
|
||||
input: Schema.Union([Schema.Number, Schema.Literal("unknown")]),
|
||||
output: Schema.Union([Schema.Number, Schema.Literal("unknown")]),
|
||||
execute: (input) => Effect.succeed(input),
|
||||
})
|
||||
expect(inputTypeScript(tool)).toContain('"unknown"')
|
||||
expect(outputTypeScript(tool)).toContain('"unknown"')
|
||||
expect(decodeInput(tool, "unknown")).toBe("unknown")
|
||||
})
|
||||
|
||||
test("anyOf with a number branch keeps sibling alternatives", () => {
|
||||
const schema = {
|
||||
anyOf: [{ type: "string" }, { type: "number" }],
|
||||
|
||||
@@ -452,12 +452,10 @@ describe("RegExp", () => {
|
||||
expect((await error(`return "aa".matchAll(/a/)`)).message).toContain("write /a/g, or use String.match")
|
||||
})
|
||||
|
||||
test("any argument is a pattern string, as new RegExp(arg) reads it", async () => {
|
||||
expect(
|
||||
await value(
|
||||
`return ["a42b".match(42)[0], "xnullx".search(null), "abc".match(undefined), [..."1a1".matchAll(1)].length]`,
|
||||
),
|
||||
).toEqual(["42", 1, [""], 2])
|
||||
test("a non-pattern argument names the expected shapes", async () => {
|
||||
const err = await error(`return "abc".match(42)`)
|
||||
expect(err.message).toContain("expects a regular expression")
|
||||
expect(err.message).toContain("not number")
|
||||
})
|
||||
|
||||
test("source and flags properties read through", async () => {
|
||||
@@ -1416,9 +1414,7 @@ describe("built-in iterators", () => {
|
||||
const logged = await run(`console.log([1].keys()); return null`)
|
||||
expect(logged.logs?.[0]).toBe("[opaque reference]")
|
||||
expect((await error(`return [1].keys() + ""`)).message).toContain("Binary operators require data values")
|
||||
expect((await error(`return [1].keys().next.call({})`)).message).toContain(
|
||||
"Iterator.prototype.next called on incompatible receiver a data object",
|
||||
)
|
||||
expect((await error(`return [1].keys().next.call({})`)).message).toContain("is not a function")
|
||||
expect((await error(`const it = [1].keys(); const next = it.next; return next()`)).message).toContain(
|
||||
"Iterator.prototype.next called on incompatible receiver undefined",
|
||||
)
|
||||
|
||||
@@ -24,9 +24,9 @@ Without them the runner registers no tests, so CI is unaffected. Licensed under
|
||||
|
||||
`script/sync-test262.ts` skips a file when its frontmatter declares a `flags`, `features`, or `includes` value the
|
||||
manifest marks unsupported, or when its code matches one of the manifest's `boundaries` patterns. The sync checks the
|
||||
checkout is at the pinned revision, so every machine runs the same files. Boundaries are
|
||||
intentional limits of the interpreter, not compatibility work: classes, prototype objects, property descriptors,
|
||||
accessors, boxed primitives, sloppy mode, `eval`, `Symbol()`, and the `$262` host API. If one
|
||||
checkout is at the pinned revision, so every machine runs the same 3993 files. Boundaries are
|
||||
intentional limits of the interpreter, not compatibility work: classes, `this`, `arguments`, prototype objects,
|
||||
property descriptors, accessors, boxed primitives, sloppy mode, `eval`, `Symbol()`, and the `$262` host API. If one
|
||||
of those decisions changes, delete its entry and re-sync; the tests are upstream, not lost.
|
||||
|
||||
## Commands
|
||||
|
||||
@@ -1,21 +1,13 @@
|
||||
{
|
||||
"revision": "250f204f23a9249ff204be2baec29600faae7b75",
|
||||
"directories": [
|
||||
"built-ins/Array/prototype",
|
||||
"built-ins/Function/prototype/apply",
|
||||
"built-ins/Function/prototype/bind",
|
||||
"built-ins/Function/prototype/call",
|
||||
"built-ins/Iterator",
|
||||
"built-ins/String/raw",
|
||||
"language/arguments-object",
|
||||
"language/expressions/tagged-template",
|
||||
"language/expressions/this",
|
||||
"language/statements"
|
||||
],
|
||||
"directories": ["built-ins/Array/prototype", "language/statements", "built-ins/Iterator"],
|
||||
"harness": ["assert.js", "sta.js", "compareArray.js", "doneprintHandle.js"],
|
||||
"flags": ["module", "raw", "noStrict"],
|
||||
"boundaries": {
|
||||
"class": "\\bclass\\s*[A-Za-z_${]",
|
||||
"this": "\\bthis\\b",
|
||||
"arguments": "\\barguments\\b",
|
||||
"call/apply/bind": "\\.(call|apply|bind)\\s*\\(",
|
||||
"accessor properties": "\\b(get|set)\\s+[\\w$\\[][^\\n(]*\\(",
|
||||
"property descriptors": "Object\\.(defineProperty|defineProperties|getOwnPropertyDescriptors?|getOwnPropertyNames|create|getPrototypeOf|setPrototypeOf|freeze|seal|preventExtensions|isFrozen|isSealed|isExtensible)\\b",
|
||||
"boxed primitives": "\\bnew\\s+(String|Number|Boolean)\\s*\\(",
|
||||
|
||||
@@ -4,92 +4,13 @@ built-ins/Array/prototype/concat/S15.4.4.4_A2_T2.js # Array.prototype.concat ca
|
||||
built-ins/Array/prototype/concat/S15.4.4.4_A3_T1.js # arr.hasOwnProperty("1") must return true Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/concat/S15.4.4.4_A3_T2.js # b.hasOwnProperty("2") must return true Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/concat/S15.4.4.4_A3_T3.js # b.hasOwnProperty("2") must return true Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/concat/call-with-boolean.js # TypeError: Array.prototype.concat called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/concat/create-ctor-non-object.js # a.concat() throws a TypeError exception Expected a TypeError to be thrown but no exception was throw
|
||||
built-ins/Array/prototype/copyWithin/call-with-boolean.js # TypeError: Array.prototype.copyWithin called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/copyWithin/coerced-values-start-change-target.js # Array.copyWithin expects start to be a number.
|
||||
built-ins/Array/prototype/copyWithin/length-near-integer-limit.js # TypeError: Array.prototype.copyWithin called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/copyWithin/return-abrupt-from-end.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/copyWithin/return-abrupt-from-start.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/copyWithin/return-abrupt-from-target.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/copyWithin/return-this.js # TypeError: Array.prototype.copyWithin called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-1-10.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-1-11.js # TypeError: Array.prototype.every called on incompatible receiver a Date.
|
||||
built-ins/Array/prototype/every/15.4.4.16-1-12.js # TypeError: Array.prototype.every called on incompatible receiver a RegExp.
|
||||
built-ins/Array/prototype/every/15.4.4.16-1-13.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-1-14.js # TypeError: Array.prototype.every called on incompatible receiver an Error.
|
||||
built-ins/Array/prototype/every/15.4.4.16-1-3.js # TypeError: Array.prototype.every called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/every/15.4.4.16-1-5.js # TypeError: Array.prototype.every called on incompatible receiver a number.
|
||||
built-ins/Array/prototype/every/15.4.4.16-1-7.js # TypeError: Array.prototype.every called on incompatible receiver a string.
|
||||
built-ins/Array/prototype/every/15.4.4.16-2-1.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-2-14.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-2-17.js # func(12, 11) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-2-19.js # TypeError: Array.prototype.every called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/every/15.4.4.16-2-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/every/15.4.4.16-2-6.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-1.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-10.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-11.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-12.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-13.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-14.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-15.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-16.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-17.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-18.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-19.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-2.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-20.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-21.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-22.js # toStringAccessed !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-24.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-25.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-29.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-3.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-4.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-5.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-6.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-7.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-8.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-3-9.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-10.js # [11].every(callbackfn, objArray) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-14.js # [11].every(callbackfn, Math) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-15.js # [11].every(callbackfn, objDate) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-16.js # [11].every(callbackfn, objRegExp) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-17.js # [11].every(callbackfn, JSON) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-18.js # [11].every(callbackfn, objError) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-19.js # [11].every(callbackfn, arg) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-2.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-22.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-23.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-24.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-3.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-4.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-5.js # TypeError: foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-6.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/every/15.4.4.16-5-9.js # [11].every(callbackfn, objFunction) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-6.js # res Expected SameValue(«true», «false») to be true
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-8.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-i-1.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-i-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-i-7.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-i-8.js # [, , , ].every(callbackfn) Expected SameValue(«true», «false») to be true
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-16.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-17.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-18.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-19.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-20.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-21.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-22.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-23.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-6.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-7.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-ii-8.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-iii-1.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-iii-2.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-iii-27.js # [11].every(callbackfn) !== true
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-iii-3.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-iii-4.js # TypeError: Array.prototype.every called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-10.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -98,66 +19,9 @@ built-ins/Array/prototype/every/15.4.4.16-8-5.js # … cannot be constructed: u
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-6.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-8.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/every/call-with-boolean.js # TypeError: Array.prototype.every called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/fill/call-with-boolean.js # TypeError: Array.prototype.fill called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/fill/length-near-integer-limit.js # TypeError: Array.prototype.fill called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/fill/return-abrupt-from-end.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/fill/return-abrupt-from-start.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/fill/return-this.js # TypeError: Array.prototype.fill called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-1-10.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-1-11.js # TypeError: Array.prototype.filter called on incompatible receiver a Date.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-1-12.js # TypeError: Array.prototype.filter called on incompatible receiver a RegExp.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-1-13.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-1-14.js # TypeError: Array.prototype.filter called on incompatible receiver an Error.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-1-3.js # TypeError: Array.prototype.filter called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-1-5.js # TypeError: Array.prototype.filter called on incompatible receiver a number.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-1-7.js # TypeError: Array.prototype.filter called on incompatible receiver a string.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-10-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/filter/15.4.4.20-2-1.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-2-14.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-2-19.js # TypeError: Array.prototype.filter called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-2-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/filter/15.4.4.20-2-6.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-1.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-10.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-11.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-12.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-13.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-14.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-15.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-16.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-17.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-18.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-19.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-2.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-20.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-21.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-22.js # firstStepOccured !== true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-23.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-24.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-25.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-3.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-4.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-5.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-6.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-7.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-3-9.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-10.js # newArr[0] Expected SameValue(«undefined», «11») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-14.js # newArr[0] Expected SameValue(«undefined», «11») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-15.js # newArr[0] Expected SameValue(«undefined», «11») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-16.js # newArr[0] Expected SameValue(«undefined», «11») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-17.js # newArr[0] Expected SameValue(«undefined», «11») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-18.js # newArr[0] Expected SameValue(«undefined», «11») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-19.js # newArr[0] Expected SameValue(«undefined», «11») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-2.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-22.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-23.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-24.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-3.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-4.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-5.js # TypeError: foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-6.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/filter/15.4.4.20-5-9.js # newArr[0] Expected SameValue(«undefined», «11») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-6-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/filter/15.4.4.20-6-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/filter/15.4.4.20-6-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -166,121 +30,11 @@ built-ins/Array/prototype/filter/15.4.4.20-6-6.js # … cannot be constructed:
|
||||
built-ins/Array/prototype/filter/15.4.4.20-6-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/filter/15.4.4.20-6-8.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-6.js # resArr.length Expected SameValue(«3», «4») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-8.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-i-1.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-i-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-i-7.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-i-8.js # newArr.length Expected SameValue(«0», «1») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-16.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-17.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-18.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-19.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-20.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-21.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-22.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-23.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-6.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-7.js # Expected a Error but got a TypeError
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-ii-8.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-1-1.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-1-2.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-1-3.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-1-4.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-2.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-28.js # newArr.length Expected SameValue(«0», «1») to be true
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-29.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-3.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-4.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-9-c-iii-5.js # TypeError: Array.prototype.filter called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/filter/call-with-boolean.js # TypeError: Array.prototype.filter called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/filter/create-ctor-non-object.js # null value Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Array/prototype/find/call-with-boolean.js # TypeError: Array.prototype.find called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/find/predicate-call-this-strict.js # Expected SameValue(«undefined», «object») to be true
|
||||
built-ins/Array/prototype/findIndex/call-with-boolean.js # TypeError: Array.prototype.findIndex called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/findIndex/predicate-call-this-strict.js # Expected SameValue(«undefined», «object») to be true
|
||||
built-ins/Array/prototype/findLast/call-with-boolean.js # TypeError: Array.prototype.findLast called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/findLast/maximum-index.js # TypeError: Array.prototype.findLast called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/findLast/predicate-call-this-strict.js # Expected SameValue(«undefined», «object») to be true
|
||||
built-ins/Array/prototype/findLastIndex/call-with-boolean.js # TypeError: Array.prototype.findLastIndex called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/findLastIndex/maximum-index.js # TypeError: Array.prototype.findLastIndex called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/findLastIndex/predicate-call-this-strict.js # Expected SameValue(«undefined», «object») to be true
|
||||
built-ins/Array/prototype/flat/array-like-objects.js # TypeError: Array.prototype.flat called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/flat/call-with-boolean.js # TypeError: Array.prototype.flat called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/flat/non-object-ctor-throws.js # null value Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Array/prototype/flat/proxy-access-count.js # ReferenceError: Unknown identifier '…'.
|
||||
built-ins/Array/prototype/flatMap/call-with-boolean.js # TypeError: Array.prototype.flatMap called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/flatMap/proxy-access-count.js # ReferenceError: Unknown identifier '…'.
|
||||
built-ins/Array/prototype/flatMap/thisArg-argument.js # Actual [undefined] and expected ["TestString"] should have the same contents. The value of actual is
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-1-10.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-1-11.js # TypeError: Array.prototype.forEach called on incompatible receiver a Date.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-1-12.js # TypeError: Array.prototype.forEach called on incompatible receiver a RegExp.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-1-13.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-1-14.js # TypeError: Array.prototype.forEach called on incompatible receiver an Error.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-1-3.js # TypeError: Array.prototype.forEach called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-1-5.js # TypeError: Array.prototype.forEach called on incompatible receiver a number.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-1-7.js # TypeError: Array.prototype.forEach called on incompatible receiver a string.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-2-1.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-2-14.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-2-17.js # func(12, 11) !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-2-19.js # TypeError: Array.prototype.forEach called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-2-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-2-6.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-1.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-10.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-11.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-12.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-13.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-14.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-15.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-16.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-17.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-18.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-19.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-2.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-20.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-21.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-23.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-24.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-25.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-3.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-4.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-5.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-6.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-7.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-3-9.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-10.js # result !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-14.js # result !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-15.js # result !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-16.js # result !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-17.js # result !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-18.js # result !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-19.js # result !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-2.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-22.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-23.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-24.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-3.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-4.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-5.js # TypeError: foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-6.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-5-9.js # result !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-5.js # callCnt Expected SameValue(«4», «5») to be true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-8.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-i-1.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-i-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-i-7.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-i-8.js # testResult !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-16.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-17.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-18.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-19.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-20.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-21.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-22.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-23.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-6.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-7.js # Expected a Error but got a TypeError
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-ii-8.js # TypeError: Array.prototype.forEach called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-10.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -290,135 +44,21 @@ built-ins/Array/prototype/forEach/15.4.4.18-8-6.js # … cannot be constructed:
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-8.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-9.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/forEach/call-with-boolean.js # TypeError: Array.prototype.forEach called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/includes/call-with-boolean.js # TypeError: Array.prototype.includes called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/includes/length-boundaries.js # TypeError: Array.prototype.includes called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/includes/return-abrupt-tointeger-fromindex.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/includes/return-abrupt-tonumber-length.js # valueOf Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/includes/tointeger-fromindex.js # Array.includes expects start index to be a number.
|
||||
built-ins/Array/prototype/includes/tolength-length.js # TypeError: Array.prototype.includes called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-1-10.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-1-11.js # TypeError: Array.prototype.indexOf called on incompatible receiver a Date.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-1-12.js # TypeError: Array.prototype.indexOf called on incompatible receiver a RegExp.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-1-13.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-1-14.js # TypeError: Array.prototype.indexOf called on incompatible receiver an Error.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-1-3.js # TypeError: Array.prototype.indexOf called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-1-5.js # TypeError: Array.prototype.indexOf called on incompatible receiver a number.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-1-7.js # TypeError: Array.prototype.indexOf called on incompatible receiver a string.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-1-9.js # TypeError: Array.prototype.indexOf called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-2-1.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-2-14.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-2-17.js # func(0, true) !== true
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-2-19.js # TypeError: Array.prototype.indexOf called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-2-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-2-6.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-1.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-10.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-11.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-12.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-13.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-14.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-15.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-16.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-17.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-18.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-19.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-2.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-20.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-21.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-22.js # toStringAccessed
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-23.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-24.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-25.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-28.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-29.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-3.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-4.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-5.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-6.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-7.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-8.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-3-9.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-10.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-11.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-2.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-3.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-4.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-5.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-6.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-7.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-8.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-4-9.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-5-23.js # Array.indexOf expects start index to be a number.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-5-24.js # toStringAccessed
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-5-25.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-9-7.js # Array assignment result contains a circular value.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-9-a-2.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-9-a-3.js # Array.indexOf expects start index to be a number.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-9-a-5.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-9-a-6.js # Array.indexOf expects start index to be a number.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-9-b-i-1.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-9-b-i-4.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-9-b-i-7.js # [, , , ].indexOf(true) Expected SameValue(«-1», «0») to be true
|
||||
built-ins/Array/prototype/indexOf/15.4.4.14-9-b-i-8.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/indexOf/call-with-boolean.js # TypeError: Array.prototype.indexOf called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/indexOf/length-near-integer-limit.js # TypeError: Array.prototype.indexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/join/S15.4.4.5_A2_T1.js # Array.prototype.join called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/join/S15.4.4.5_A2_T4.js # Array.prototype.join called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/join/S15.4.4.5_A3.1_T2.js # Array.join expects zero arguments or one string separator.
|
||||
built-ins/Array/prototype/join/S15.4.4.5_A3.2_T2.js # x.join() must return "*" Expected SameValue(«"[object Object]"», «"*"») to be true
|
||||
built-ins/Array/prototype/join/S15.4.4.5_A4_T3.js # Array.prototype.join called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/join/S15.4.4.5_A5_T1.js # #1: Array.prototype[1] = 1; x = [0]; x.length = 2; x.join() === "0,1". Actual: 0,
|
||||
built-ins/Array/prototype/join/call-with-boolean.js # TypeError: Array.prototype.join called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-10.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-11.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a Date.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-12.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a RegExp.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-13.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-14.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver an Error.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-3.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-5.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a number.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-7.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a string.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-1-9.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-2-1.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-2-14.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-2-17.js # func(0, targetObj) !== true
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-2-19.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-2-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-2-6.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-1.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-10.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-11.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-12.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-13.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-14.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-15.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-16.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-17.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-19.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-2.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-20.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-21.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-22.js # toStringAccessed
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-23.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-24.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-25.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-28.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-3.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-4.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-5.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-6.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-7.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-3-9.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-10.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-11.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-2.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-3.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-4.js # TypeError: foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-5.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-6.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-7.js # TypeError: foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-8.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-4-9.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-5-21.js # Array.lastIndexOf expects start index to be a number.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-5-22.js # Array.lastIndexOf expects start index to be a number.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-5-23.js # Array.lastIndexOf expects start index to be a number.
|
||||
@@ -426,103 +66,12 @@ built-ins/Array/prototype/lastIndexOf/15.4.4.15-5-24.js # toStringAccessed
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-5-25.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-5-4.js # a.lastIndexOf(2,undefined) Expected SameValue(«1», «-1») to be true
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-8-7.js # Array assignment result contains a circular value.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-8-a-2.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-8-a-3.js # Array.lastIndexOf expects start index to be a number.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-8-a-5.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-8-b-i-1.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-8-b-i-4.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-8-b-i-7.js # [, , , ].lastIndexOf(true) Expected SameValue(«-1», «0») to be true
|
||||
built-ins/Array/prototype/lastIndexOf/15.4.4.15-8-b-i-8.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/lastIndexOf/call-with-boolean.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/lastIndexOf/length-near-integer-limit.js # TypeError: Array.prototype.lastIndexOf called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-1-10.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-1-11.js # TypeError: Array.prototype.map called on incompatible receiver a Date.
|
||||
built-ins/Array/prototype/map/15.4.4.19-1-12.js # TypeError: Array.prototype.map called on incompatible receiver a RegExp.
|
||||
built-ins/Array/prototype/map/15.4.4.19-1-13.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-1-14.js # TypeError: Array.prototype.map called on incompatible receiver an Error.
|
||||
built-ins/Array/prototype/map/15.4.4.19-1-3.js # TypeError: Array.prototype.map called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/map/15.4.4.19-1-5.js # TypeError: Array.prototype.map called on incompatible receiver a number.
|
||||
built-ins/Array/prototype/map/15.4.4.19-1-7.js # TypeError: Array.prototype.map called on incompatible receiver a string.
|
||||
built-ins/Array/prototype/map/15.4.4.19-2-1.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-2-14.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-2-19.js # TypeError: Array.prototype.map called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/map/15.4.4.19-2-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-2-6.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-1.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-10.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-11.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-12.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-13.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-14.js # Expected a RangeError but got a TypeError
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-15.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-16.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-17.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-18.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-19.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-2.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-20.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-21.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-23.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-24.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-25.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-28.js # Expected a RangeError but got a TypeError
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-29.js # Expected a RangeError but got a TypeError
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-3.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-4.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-5.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-6.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-7.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-8.js # Expected a RangeError but got a TypeError
|
||||
built-ins/Array/prototype/map/15.4.4.19-3-9.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-10.js # testResult[0] Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-14.js # testResult[0] Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-15.js # testResult[0] Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-16.js # testResult[0] Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-17.js # testResult[0] Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-18.js # testResult[0] Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-19.js # testResult[0] Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-2.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-22.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-23.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-24.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-3.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-4.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-5.js # TypeError: foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-6.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/map/15.4.4.19-5-9.js # testResult[0] Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-6.js # resArr[4] Expected SameValue(«undefined», «1») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-8.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-i-1.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-i-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-i-7.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-i-8.js # newArr[1] Expected SameValue(«13», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-16.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-17.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-18.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-19.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-20.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-21.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-22.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-23.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-6.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-7.js # Expected a Error but got a TypeError
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-ii-8.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-iii-2.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-iii-3.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-iii-4.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-iii-5.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-10.js # TypeError: Foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-11.js # TypeError: Foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-12.js # TypeError: Foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-5.js # TypeError: Array.prototype.map called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-6.js # TypeError: Foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-7.js # TypeError: Foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-8.js # TypeError: Foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-9.js # TypeError: Foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/map/call-with-boolean.js # TypeError: Array.prototype.map called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/map/create-ctor-non-object.js # null value Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Array/prototype/map/create-non-array-invalid-len.js # Expected a RangeError but got a TypeError
|
||||
built-ins/Array/prototype/pop/S15.4.4.6_A2_T1.js # Array.prototype.pop called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/pop/S15.4.4.6_A2_T4.js # Array.prototype.pop called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/pop/S15.4.4.6_A3_T1.js # Array.prototype.pop called on incompatible receiver a data object.
|
||||
@@ -530,9 +79,6 @@ built-ins/Array/prototype/pop/S15.4.4.6_A3_T2.js # Array.prototype.pop called o
|
||||
built-ins/Array/prototype/pop/S15.4.4.6_A3_T3.js # Array.prototype.pop called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/pop/S15.4.4.6_A4_T1.js # #1: Array.prototype[1] = 1; x = [0]; x.length = 2; x.pop() === 1. Actual: undefined
|
||||
built-ins/Array/prototype/pop/S15.4.4.6_A4_T2.js # Array.prototype.pop called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/pop/call-with-boolean.js # TypeError: Array.prototype.pop called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/pop/clamps-to-integer-limit.js # TypeError: Array.prototype.pop called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/pop/length-near-integer-limit.js # TypeError: Array.prototype.pop called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/push/S15.4.4.7_A2_T1.js # Array.prototype.push called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/push/S15.4.4.7_A2_T3.js # Array.prototype.push called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/push/S15.4.4.7_A3.js # The value of x[4294967295] is expected to be "x" Expected SameValue(«undefined», «"x"») to be true
|
||||
@@ -540,51 +86,10 @@ built-ins/Array/prototype/push/S15.4.4.7_A4_T1.js # Array.prototype.push called
|
||||
built-ins/Array/prototype/push/S15.4.4.7_A4_T2.js # Array.prototype.push called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/push/S15.4.4.7_A4_T3.js # Array.prototype.push called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/push/S15.4.4.7_A5_T1.js # Array.prototype.push called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/push/call-with-boolean.js # TypeError: Array.prototype.push called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/push/clamps-to-integer-limit.js # TypeError: Array.prototype.push called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/push/length-near-integer-limit.js # TypeError: Array.prototype.push called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-1-10.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-1-11.js # TypeError: Array.prototype.reduce called on incompatible receiver a Date.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-1-12.js # TypeError: Array.prototype.reduce called on incompatible receiver a RegExp.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-1-13.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-1-14.js # TypeError: Array.prototype.reduce called on incompatible receiver an Error.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-1-3.js # TypeError: Array.prototype.reduce called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-1-5.js # TypeError: Array.prototype.reduce called on incompatible receiver a number.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-1-7.js # TypeError: Array.prototype.reduce called on incompatible receiver a string.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-10-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-10-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-10-6.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-10-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-2-1.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-2-14.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-2-17.js # func(12, 11) Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-2-19.js # TypeError: Array.prototype.reduce called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-2-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-2-6.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-1.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-10.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-11.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-12.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-13.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-14.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-15.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-16.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-17.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-18.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-19.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-2.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-20.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-21.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-22.js # toStringAccessed !== true
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-23.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-24.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-25.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-3.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-4.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-5.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-6.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-7.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-3-9.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-5-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-5-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-5-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -600,77 +105,14 @@ built-ins/Array/prototype/reduce/15.4.4.21-7-6.js # … cannot be constructed:
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-7-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-7-8.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-7-9.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-8-b-iii-1-1.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-8-b-iii-1-29.js # TypeError: Array.prototype.reduce called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-8-b-iii-1-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-8-b-iii-1-7.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-8-b-iii-1-8.js # Array.reduce of an empty array with no initial value.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-8-c-4.js # Array.reduce of an empty array with no initial value.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-6.js # res Expected SameValue(«"123"», «"1235"») to be true
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-i-1.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-i-29.js # TypeError: Array.prototype.reduce called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-i-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-i-7.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-i-8.js # testResult !== true
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-16.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-18.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-20.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-21.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-22.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-23.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-24.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-25.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-26.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-30.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-31.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-32.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-33.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-34.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-35.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-37.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-7.js # Expected a Error but got a TypeError
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-9-c-ii-8.js # TypeError: Array.prototype.reduce called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduce/call-with-boolean.js # TypeError: Array.prototype.reduce called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-1-10.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-1-11.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a Date.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-1-12.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a RegExp.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-1-13.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-1-14.js # TypeError: Array.prototype.reduceRight called on incompatible receiver an Error.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-1-3.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-1-5.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a number.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-1-7.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a string.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-10-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-10-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-10-6.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-10-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-2-1.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-2-14.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-2-19.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-2-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-2-6.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-1.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-10.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-11.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-12.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-13.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-14.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-15.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-16.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-17.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-18.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-19.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-2.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-20.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-21.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-22.js # toStringAccessed !== true
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-24.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-25.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-3.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-4.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-5.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-6.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-7.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-3-9.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-5-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-5-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-5-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -686,50 +128,20 @@ built-ins/Array/prototype/reduceRight/15.4.4.22-7-6.js # … cannot be construc
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-7-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-7-8.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-7-9.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-8-b-iii-1-1.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-8-b-iii-1-29.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-8-b-iii-1-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-8-b-iii-1-7.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-8-b-iii-1-8.js # Array.reduceRight of an empty array with no initial value.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-8-c-4.js # Array.reduceRight of an empty array with no initial value.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-6.js # res Expected SameValue(«"91"», «"151"») to be true
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-i-1.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-i-29.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-i-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-i-7.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-i-8.js # testResult !== true
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-16.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-20.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-21.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-22.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-23.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-24.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-25.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-26.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-30.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-31.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-32.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-33.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-34.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-35.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-37.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-7.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-9-c-ii-8.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reduceRight/call-with-boolean.js # TypeError: Array.prototype.reduceRight called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/reduceRight/length-near-integer-limit.js # The value of acc.length is expected to be 2 Expected SameValue(«undefined», «2») to be true
|
||||
built-ins/Array/prototype/reverse/S15.4.4.8_A2_T1.js # Array.prototype.reverse called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reverse/S15.4.4.8_A3_T3.js # Array.prototype.reverse called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reverse/S15.4.4.8_A4_T1.js # #1: Array.prototype[1] = 1; x = [0]; x.length = 2; x.reverse(); x[0] === 1. Actual: undefined
|
||||
built-ins/Array/prototype/reverse/S15.4.4.8_A4_T2.js # Array.prototype.reverse called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/reverse/call-with-boolean.js # TypeError: Array.prototype.reverse called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-object.js # TypeError: Only init object properties are supported.
|
||||
built-ins/Array/prototype/shift/S15.4.4.9_A2_T1.js # Array.prototype.shift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/shift/S15.4.4.9_A2_T4.js # Array.prototype.shift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/shift/S15.4.4.9_A2_T5.js # Array.prototype.shift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/shift/S15.4.4.9_A3_T3.js # Array.prototype.shift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/shift/S15.4.4.9_A4_T1.js # #2: Array.prototype[1] = 1; x = [0]; x.length = 2; x.shift(); x[0] === 1. Actual: undefined
|
||||
built-ins/Array/prototype/shift/S15.4.4.9_A4_T2.js # Array.prototype.shift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/shift/call-with-boolean.js # TypeError: Array.prototype.shift called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/slice/S15.4.4.10_A2.2_T5.js # Array.slice expects end to be a number.
|
||||
built-ins/Array/prototype/slice/S15.4.4.10_A2_T1.js # Array.prototype.slice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/slice/S15.4.4.10_A2_T2.js # Array.prototype.slice called on incompatible receiver a data object.
|
||||
@@ -741,89 +153,9 @@ built-ins/Array/prototype/slice/S15.4.4.10_A3_T1.js # Expected a RangeError but
|
||||
built-ins/Array/prototype/slice/S15.4.4.10_A3_T2.js # Expected a RangeError but got a TypeError
|
||||
built-ins/Array/prototype/slice/S15.4.4.10_A3_T3.js # Array.prototype.slice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/slice/S15.4.4.10_A4_T1.js # #3: Array.prototype[1] = 1; x = [0]; x.length = 2; var arr = x.slice(); arr.hasOwnProperty('…') ===
|
||||
built-ins/Array/prototype/slice/call-with-boolean.js # TypeError: Array.prototype.slice called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/slice/create-ctor-non-object.js # null value Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Array/prototype/slice/length-exceeding-integer-limit-proxied-array.js # ReferenceError: Unknown identifier '…'.
|
||||
built-ins/Array/prototype/slice/length-exceeding-integer-limit.js # TypeError: Array.prototype.slice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-1-10.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-1-11.js # TypeError: Array.prototype.some called on incompatible receiver a Date.
|
||||
built-ins/Array/prototype/some/15.4.4.17-1-12.js # TypeError: Array.prototype.some called on incompatible receiver a RegExp.
|
||||
built-ins/Array/prototype/some/15.4.4.17-1-13.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-1-14.js # TypeError: Array.prototype.some called on incompatible receiver an Error.
|
||||
built-ins/Array/prototype/some/15.4.4.17-1-3.js # TypeError: Array.prototype.some called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/some/15.4.4.17-1-5.js # TypeError: Array.prototype.some called on incompatible receiver a number.
|
||||
built-ins/Array/prototype/some/15.4.4.17-1-7.js # TypeError: Array.prototype.some called on incompatible receiver a string.
|
||||
built-ins/Array/prototype/some/15.4.4.17-2-1.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-2-14.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-2-17.js # func(9, 11) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-2-19.js # TypeError: Array.prototype.some called on incompatible receiver a function.
|
||||
built-ins/Array/prototype/some/15.4.4.17-2-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/some/15.4.4.17-2-6.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-1.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-10.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-11.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-12.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-13.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-14.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-15.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-16.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-17.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-18.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-19.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-2.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-20.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-21.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-22.js # toStringAccessed !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-23.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-24.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-25.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-28.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-29.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-3.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-4.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-5.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-6.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-7.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-8.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-3-9.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-10.js # [11].some(callbackfn, objArray) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-14.js # [11].some(callbackfn, Math) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-15.js # [11].some(callbackfn, objDate) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-16.js # [11].some(callbackfn, objRegExp) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-17.js # [11].some(callbackfn, JSON) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-18.js # [11].some(callbackfn, objError) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-19.js # [11].some(callbackfn, arg) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-2.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-22.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-23.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-24.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-3.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-4.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-5.js # TypeError: foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-6.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
built-ins/Array/prototype/some/15.4.4.17-5-9.js # [11].some(callbackfn, objFunction) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-6.js # res Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-8.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-i-1.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-i-3.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-i-7.js # TypeError: Con cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-i-8.js # [, ].some(callbackfn) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-16.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-17.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-18.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-19.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-20.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-21.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-22.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-23.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-6.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-7.js # Expected a Error but got a TypeError
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-ii-8.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-iii-1.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-iii-2.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-iii-26.js # [11].some(callbackfn) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-iii-3.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-iii-4.js # TypeError: Array.prototype.some called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-10.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -832,7 +164,6 @@ built-ins/Array/prototype/some/15.4.4.17-8-5.js # … cannot be constructed: us
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-6.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-8.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/some/call-with-boolean.js # TypeError: Array.prototype.some called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/sort/S15.4.4.11_A2.1_T3.js # #1: Check ToString operator
|
||||
built-ins/Array/prototype/sort/S15.4.4.11_A2.2_T3.js # #1: Check ToString operator
|
||||
built-ins/Array/prototype/sort/S15.4.4.11_A3_T1.js # Array.prototype.sort called on incompatible receiver a data object.
|
||||
@@ -851,76 +182,27 @@ built-ins/Array/prototype/splice/S15.4.4.12_A3_T3.js # Array.prototype.splice c
|
||||
built-ins/Array/prototype/splice/S15.4.4.12_A4_T1.js # Array.prototype.splice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/splice/S15.4.4.12_A4_T2.js # Array.prototype.splice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/splice/S15.4.4.12_A4_T3.js # Array.prototype.splice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/splice/call-with-boolean.js # TypeError: Array.prototype.splice called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/splice/clamps-length-to-integer-limit.js # TypeError: Array.prototype.splice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/splice/create-ctor-non-object.js # null value Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Array/prototype/splice/length-and-deleteCount-exceeding-integer-limit.js # TypeError: Array.prototype.splice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/splice/length-exceeding-integer-limit-shrink-array.js # TypeError: Array.prototype.splice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/splice/length-near-integer-limit-grow-array.js # TypeError: Array.prototype.splice called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/toLocaleString/S15.4.4.3_A3_T1.js # #1: var n = 0; var obj = {toLocaleString: function() {n++}}; Array.prototype[1] = obj; x = [obj]; x.
|
||||
built-ins/Array/prototype/toReversed/holes-not-preserved.js # Actual [4, undefined, 2, undefined, 0] and expected [4, 3, 2, undefined, 0] should have the same con
|
||||
built-ins/Array/prototype/toReversed/length-casted-to-zero.js # TypeError: Array.prototype.toReversed called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/toReversed/length-exceeding-array-length-limit.js # TypeError: Only init object properties are supported.
|
||||
built-ins/Array/prototype/toReversed/length-tolength.js # TypeError: Array.prototype.toReversed called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/toReversed/this-value-boolean.js # TypeError: Array.prototype.toReversed called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/toSorted/holes-not-preserved.js # Actual [1, 3, 4, undefined, undefined] and expected [1, 2, 3, 4, undefined] should have the same con
|
||||
built-ins/Array/prototype/toSorted/length-casted-to-zero.js # TypeError: Array.prototype.toSorted called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/toSorted/length-exceeding-array-length-limit.js # TypeError: Only init object properties are supported.
|
||||
built-ins/Array/prototype/toSorted/length-tolength.js # TypeError: Array.prototype.toSorted called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/toSorted/this-value-boolean.js # TypeError: Array.prototype.toSorted called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/toSpliced/holes-not-preserved.js # Actual [0, undefined, 2, undefined, 4] and expected [0, undefined, 2, 3, 4] should have the same con
|
||||
built-ins/Array/prototype/toSpliced/length-casted-to-zero.js # TypeError: Array.prototype.toSpliced called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/toSpliced/length-clamped-to-2pow53minus1.js # TypeError: Array.prototype.toSpliced called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/toSpliced/length-exceeding-array-length-limit.js # TypeError: Only init object properties are supported.
|
||||
built-ins/Array/prototype/toSpliced/length-tolength.js # TypeError: Array.prototype.toSpliced called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/toSpliced/this-value-boolean.js # TypeError: Array.prototype.toSpliced called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/toString/S15.4.4.2_A1_T4.js # Expected a Test262Error to be thrown but no exception was thrown at all
|
||||
built-ins/Array/prototype/toString/S15.4.4.2_A3_T1.js # #1: Array.prototype[1] = 1; x = [0]; x.length = 2; x.toString() === "0,1". Actual: 0,
|
||||
built-ins/Array/prototype/toString/call-with-boolean.js # TypeError: Array.prototype.toString called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/unshift/S15.4.4.13_A2_T1.js # Array.prototype.unshift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/unshift/S15.4.4.13_A2_T3.js # Array.prototype.unshift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/unshift/S15.4.4.13_A3_T2.js # Array.prototype.unshift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/unshift/S15.4.4.13_A4_T1.js # Array.prototype.unshift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/unshift/S15.4.4.13_A4_T2.js # #3: Array.prototype[0] = 1; x = []; x.length = 1; x.unshift(0); x[1] === 1. Actual: undefined
|
||||
built-ins/Array/prototype/unshift/call-with-boolean.js # TypeError: Array.prototype.unshift called on incompatible receiver a boolean.
|
||||
built-ins/Array/prototype/unshift/clamps-to-integer-limit.js # TypeError: Array.prototype.unshift called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/unshift/length-near-integer-limit.js # TypeError: Only init object properties are supported.
|
||||
built-ins/Array/prototype/with/length-exceeding-array-length-limit.js # TypeError: Only init object properties are supported.
|
||||
built-ins/Array/prototype/with/length-tolength.js # TypeError: Array.prototype.with called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/with/this-value-boolean.js # TypeError: Array.prototype.with called on incompatible receiver a boolean.
|
||||
built-ins/Function/prototype/bind/15.3.4.5-2-6.js # TypeError: Object(number) wrapper objects are not supported; use the primitive value directly.
|
||||
built-ins/Function/prototype/bind/15.3.4.5-20-2.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Function/prototype/bind/15.3.4.5-20-3.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Function/prototype/bind/15.3.4.5-21-2.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Function/prototype/bind/15.3.4.5-21-3.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Function/prototype/bind/S15.3.4.5_A1.js # baz() throws a TypeError exception Expected a TypeError to be thrown but no exception was thrown at
|
||||
built-ins/Function/prototype/bind/S15.3.4.5_A2.js # baz() throws a TypeError exception Expected a TypeError to be thrown but no exception was thrown at
|
||||
built-ins/Iterator/from/return-method-returns-iterator-result.js # Iterator next must be a function.
|
||||
built-ins/Iterator/prototype/drop/limit-tonumber-throws.js # Expected a Test262Error but got a RangeError
|
||||
built-ins/Iterator/prototype/drop/limit-tonumber.js # Iterator.prototype.drop expects a non-negative count, received NaN.
|
||||
built-ins/Iterator/prototype/drop/this-non-callable-next.js # TypeError: Iterator next must be a function.
|
||||
built-ins/Iterator/prototype/filter/this-non-callable-next.js # TypeError: Iterator next must be a function.
|
||||
built-ins/Iterator/prototype/flatMap/this-non-callable-next.js # TypeError: Iterator next must be a function.
|
||||
built-ins/Iterator/prototype/map/this-non-callable-next.js # TypeError: Iterator next must be a function.
|
||||
built-ins/Iterator/prototype/take/limit-tonumber-throws.js # Expected a Test262Error but got a RangeError
|
||||
built-ins/Iterator/prototype/take/limit-tonumber.js # Iterator.prototype.take expects a non-negative count, received NaN.
|
||||
built-ins/Iterator/prototype/take/this-non-callable-next.js # TypeError: Iterator next must be a function.
|
||||
language/arguments-object/10.6-13-c-1-s.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/arguments-object/10.6-14-c-4-s.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/arguments-object/10.6-2gs.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/arguments-object/S10.6_A3_T1.js # #1: arguments object doesn't exists
|
||||
language/arguments-object/S10.6_A5_T3.js # #1: arguments object don't exists
|
||||
language/arguments-object/S10.6_A5_T4.js # #1: arguments object don't exists
|
||||
language/expressions/tagged-template/constructor-invocation.js # The called value cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/expressions/tagged-template/template-object-frozen-strict.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/expressions/this/11.1.1-1.js # Expected SameValue(«undefined», «undefined») to be false
|
||||
language/statements/async-generator/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/async-generator/dstr/ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/async-generator/dstr/dflt-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/async-generator/dstr/dflt-ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/async-generator/return-undefined-implicit-and-explicit.js # Actual ["tick 1", "tick 2", "g1 ret", "g2 ret", "g3 ret", "g4 ret"] and expected ["tick 1", "g1 ret"
|
||||
language/statements/const/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/const/dstr/ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/for-await-of/async-func-decl-dstr-obj-empty-bool.js # TypeError: Object destructuring requires a data object or array value, received a boolean.
|
||||
language/statements/for-await-of/async-func-decl-dstr-obj-empty-num.js # TypeError: Object destructuring requires a data object or array value, received a number.
|
||||
language/statements/for-await-of/async-func-decl-dstr-obj-empty-string.js # TypeError: Object destructuring requires a data object or array value, received a string.
|
||||
@@ -931,89 +213,48 @@ language/statements/for-await-of/async-gen-decl-dstr-obj-empty-num.js # TypeErr
|
||||
language/statements/for-await-of/async-gen-decl-dstr-obj-empty-string.js # TypeError: Object destructuring requires a data object or array value, received a string.
|
||||
language/statements/for-await-of/async-gen-decl-dstr-obj-rest-number.js # TypeError: Object destructuring requires a data object or array value, received a number.
|
||||
language/statements/for-await-of/async-gen-decl-dstr-obj-rest-str-val.js # TypeError: Object destructuring requires a data object or array value, received a string.
|
||||
language/statements/for-in/S12.6.4_A6.1.js # TypeError: FACTORY cannot be constructed: user-defined constructors and classes are not supported. C
|
||||
language/statements/for-in/S12.6.4_A6.js # TypeError: FACTORY cannot be constructed: user-defined constructors and classes are not supported. C
|
||||
language/statements/for-in/head-lhs-member.js # Unsupported for...in binding.
|
||||
language/statements/for-of/dstr/array-elem-iter-rtrn-close-err.js # Iterator next must be a function.
|
||||
language/statements/for-of/dstr/array-elem-iter-thrw-close-err.js # Expected SameValue(«1», «0») to be true
|
||||
language/statements/for-of/dstr/array-elem-iter-thrw-close.js # Expected SameValue(«1», «0») to be true
|
||||
language/statements/for-of/dstr/array-elem-trlg-iter-list-thrw-close-err.js # Expected SameValue(«1», «0») to be true
|
||||
language/statements/for-of/dstr/array-elem-trlg-iter-list-thrw-close.js # Expected SameValue(«1», «0») to be true
|
||||
language/statements/for-of/dstr/array-elem-trlg-iter-rest-rtrn-close-err.js # Expected a Test262Error to be thrown but no exception was thrown at all
|
||||
language/statements/for-of/dstr/array-elem-trlg-iter-rest-rtrn-close-null.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/for-of/dstr/array-elem-trlg-iter-rest-rtrn-close.js # Expected SameValue(«11», «1») to be true
|
||||
language/statements/for-of/dstr/array-elem-trlg-iter-rest-thrw-close-err.js # Expected SameValue(«11», «1») to be true
|
||||
language/statements/for-of/dstr/array-elem-trlg-iter-rest-thrw-close.js # Expected SameValue(«11», «1») to be true
|
||||
language/statements/for-of/dstr/array-rest-iter-rtrn-close-err.js # Iterator next must be a function.
|
||||
language/statements/for-of/dstr/array-rest-iter-rtrn-close-null.js # Iterator next must be a function.
|
||||
language/statements/for-of/dstr/array-rest-iter-rtrn-close.js # Test262Error
|
||||
language/statements/for-of/dstr/array-rest-iter-thrw-close-err.js # Expected SameValue(«11», «0») to be true
|
||||
language/statements/for-of/dstr/array-rest-iter-thrw-close.js # Expected SameValue(«11», «0») to be true
|
||||
language/statements/for-of/dstr/array-rest-lref-err.js # Expected SameValue(«1», «0») to be true
|
||||
language/statements/for-of/dstr/const-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/for-of/dstr/const-ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/for-of/dstr/let-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/for-of/dstr/let-ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/for-of/dstr/obj-empty-bool.js # Object destructuring requires a data object or array value, received a boolean.
|
||||
language/statements/for-of/dstr/obj-empty-num.js # Object destructuring requires a data object or array value, received a number.
|
||||
language/statements/for-of/dstr/obj-empty-string.js # Object destructuring requires a data object or array value, received a string.
|
||||
language/statements/for-of/dstr/obj-rest-number.js # Object destructuring requires a data object or array value, received a number.
|
||||
language/statements/for-of/dstr/obj-rest-str-val.js # Object destructuring requires a data object or array value, received a string.
|
||||
language/statements/for-of/dstr/var-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/for-of/dstr/var-ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/for-of/throw-from-catch.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
language/statements/for-of/throw-from-finally.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
language/statements/for-of/throw.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
language/statements/for/dstr/const-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/for/dstr/const-ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/for/dstr/let-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/for/dstr/let-ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/for/dstr/var-ary-init-iter-get-err-array-prototype.js # Expected a TypeError but got a ReferenceError
|
||||
language/statements/for/dstr/var-ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/function/13.2-1-s.js # TypeError: foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
language/statements/function/13.2-19-b-3gs.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/function/13.2-2-s.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/function/13.2-3-s.js # TypeError: foo cannot be constructed: user-defined constructors and classes are not supported. Call
|
||||
language/statements/function/13.2-4-s.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/function/S13.2.2_A10.js # #1: var obj = new FACTORY() does not lead to throwing exception. Actual: Exception is TypeError: FAC
|
||||
language/statements/function/S13.2.2_A12.js # #1: var obj = new FACTORY() does not lead to throwing exception. Actual: Exception is TypeError: FAC
|
||||
language/statements/function/S13.2.2_A15_T1.js # TypeError: __FACTORY cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/statements/function/S13.2.2_A15_T2.js # TypeError: __FACTORY cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/statements/function/S13.2.2_A15_T3.js # TypeError: __FACTORY cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/statements/function/S13.2.2_A15_T4.js # TypeError: __FACTORY cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/statements/function/S13.2.2_A16_T1.js # TypeError: The called value cannot be constructed: user-defined constructors and classes are not sup
|
||||
language/statements/function/S13.2.2_A16_T2.js # TypeError: The called value cannot be constructed: user-defined constructors and classes are not sup
|
||||
language/statements/function/S13.2.2_A16_T3.js # TypeError: The called value cannot be constructed: user-defined constructors and classes are not sup
|
||||
language/statements/function/S13.2.2_A1_T1.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
language/statements/function/S13.2.2_A1_T2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
language/statements/function/S13.2.2_A2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
language/statements/function/S13.2.2_A3_T1.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
language/statements/function/S13.2.2_A3_T2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
language/statements/function/S13.2.2_A4_T1.js # TypeError: __FACTORY cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/statements/function/S13.2.2_A4_T2.js # TypeError: __FACTORY cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/statements/function/S13.2.2_A5_T1.js # TypeError: __FACTORY cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/statements/function/S13.2.2_A5_T2.js # TypeError: __FACTORY cannot be constructed: user-defined constructors and classes are not supported.
|
||||
language/statements/function/S13.2.2_A6_T1.js # TypeError: __func cannot be constructed: user-defined constructors and classes are not supported. Ca
|
||||
language/statements/function/S13.2.2_A6_T2.js # TypeError: __func cannot be constructed: user-defined constructors and classes are not supported. Ca
|
||||
language/statements/function/S13.2.2_A7_T1.js # TypeError: __func cannot be constructed: user-defined constructors and classes are not supported. Ca
|
||||
language/statements/function/S13.2.2_A7_T2.js # TypeError: __func cannot be constructed: user-defined constructors and classes are not supported. Ca
|
||||
language/statements/function/S13.2.2_A8_T1.js # TypeError: __func cannot be constructed: user-defined constructors and classes are not supported. Ca
|
||||
language/statements/function/S13.2.2_A8_T2.js # TypeError: __func cannot be constructed: user-defined constructors and classes are not supported. Ca
|
||||
language/statements/function/S13.2_A1_T1.js # #1: __func.prototype !== undefined
|
||||
language/statements/function/S13.2_A1_T2.js # #1: __func.prototype !== undefined
|
||||
language/statements/function/S13.2_A4_T1.js # Unknown identifier '…'.
|
||||
language/statements/function/S13.2_A4_T2.js # #1: typeof __gunc.prototype === '…'. Actual: typeof __gunc.prototype ===undefined
|
||||
language/statements/function/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/function/dstr/ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/function/dstr/dflt-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/function/dstr/dflt-ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/generators/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/generators/dstr/ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/generators/dstr/dflt-ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/generators/dstr/dflt-ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/generators/restricted-properties.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/labeled/value-await-non-module.js # Failed to parse TypeScript: Expression expected.
|
||||
language/statements/let/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/let/dstr/ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/return/S12.9_A1_T1.js # expected SyntaxError but the program ran
|
||||
language/statements/return/S12.9_A1_T10.js # expected SyntaxError but the program ran
|
||||
language/statements/return/S12.9_A1_T2.js # expected SyntaxError but the program ran
|
||||
@@ -1026,10 +267,5 @@ language/statements/return/S12.9_A1_T8.js # expected SyntaxError but the progra
|
||||
language/statements/return/S12.9_A1_T9.js # expected SyntaxError but the program ran
|
||||
language/statements/switch/S12.11_A1_T4.js # Switch discriminants must be data values.
|
||||
language/statements/switch/scope-lex-open-dflt.js # Switch discriminants must be data values.
|
||||
language/statements/try/S12.14_A17.js # TypeError: Integer cannot be constructed: user-defined constructors and classes are not supported. C
|
||||
language/statements/try/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/try/dstr/ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
language/statements/variable/S12.2_A11.js # TypeError: Cannot read properties of undefined (reading '…').
|
||||
language/statements/variable/S12.2_A9.js # #1: When using property attributes, {DontEnum} not used
|
||||
language/statements/variable/dstr/ary-init-iter-get-err-array-prototype.js # Expected a TypeError to be thrown but no exception was thrown at all
|
||||
language/statements/variable/dstr/ary-ptrn-elem-id-iter-val-array-prototype.js # Expected SameValue(«3», «42») to be true
|
||||
|
||||
@@ -98,7 +98,8 @@
|
||||
"@types/bun": "catalog:",
|
||||
"@types/node": "catalog:",
|
||||
"@types/which": "3.0.4",
|
||||
"drizzle-kit": "catalog:"
|
||||
"drizzle-kit": "catalog:",
|
||||
"fast-check": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/cohere": "3.0.27",
|
||||
@@ -127,7 +128,7 @@
|
||||
"drizzle-orm": "catalog:",
|
||||
"effect": "catalog:",
|
||||
"fuzzysort": "3.1.0",
|
||||
"gitlab-ai-provider": "6.16.0",
|
||||
"gitlab-ai-provider": "6.12.1",
|
||||
"google-auth-library": "10.5.0",
|
||||
"gray-matter": "4.0.3",
|
||||
"htmlparser2": "8.0.2",
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "sqlite",
|
||||
"id": "e98619ef-c334-45e3-8c48-9932ed1ef290",
|
||||
"prevIds": ["be60f352-8da1-40e1-8d70-dc41121cfbc5"],
|
||||
"id": "be60f352-8da1-40e1-8d70-dc41121cfbc5",
|
||||
"prevIds": ["3fb67508-0196-4bae-b2bd-c08ece7583fd"],
|
||||
"ddl": [
|
||||
{
|
||||
"name": "account_state",
|
||||
@@ -700,16 +700,6 @@
|
||||
"entityType": "columns",
|
||||
"table": "project"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "0",
|
||||
"generated": null,
|
||||
"name": "time_active",
|
||||
"entityType": "columns",
|
||||
"table": "project"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"notNull": true,
|
||||
|
||||
+14
-39
@@ -705,7 +705,7 @@ function metadataProviderOptions(input: ProviderMetadata | undefined): SharedV3P
|
||||
}
|
||||
|
||||
function streamLanguage(language: LanguageModelV3, options: LanguageModelV3CallOptions, http?: HttpMiddleware) {
|
||||
const state: StreamState = { step: 0, toolNames: {}, open: {} }
|
||||
const state = { step: 0, toolNames: {} as Record<string, string> }
|
||||
return Stream.concat(
|
||||
Stream.make(LLMEvent.stepStart({ index: state.step })),
|
||||
Stream.unwrap(
|
||||
@@ -731,16 +731,8 @@ function streamLanguage(language: LanguageModelV3, options: LanguageModelV3CallO
|
||||
)
|
||||
}
|
||||
|
||||
type Fragment = "text" | "reasoning"
|
||||
|
||||
type StreamState = {
|
||||
step: number
|
||||
toolNames: Record<string, string>
|
||||
open: Partial<Record<Fragment, string>>
|
||||
}
|
||||
|
||||
function streamPartEvents(
|
||||
state: StreamState,
|
||||
state: { step: number; toolNames: Record<string, string> },
|
||||
event: LanguageModelV3StreamPart,
|
||||
): Effect.Effect<ReadonlyArray<LLMEvent>, AIError> {
|
||||
switch (event.type) {
|
||||
@@ -752,10 +744,11 @@ function streamPartEvents(
|
||||
case "tool-approval-request":
|
||||
return Effect.succeed([])
|
||||
case "text-start":
|
||||
return Effect.succeed(openFragment(state, "text", event.id, providerMetadata(event.providerMetadata)))
|
||||
return Effect.succeed([
|
||||
LLMEvent.textStart({ id: event.id, providerMetadata: providerMetadata(event.providerMetadata) }),
|
||||
])
|
||||
case "text-delta":
|
||||
return Effect.succeed([
|
||||
...openFragment(state, "text", event.id),
|
||||
LLMEvent.textDelta({
|
||||
id: event.id,
|
||||
text: event.delta,
|
||||
@@ -763,12 +756,15 @@ function streamPartEvents(
|
||||
}),
|
||||
])
|
||||
case "text-end":
|
||||
return Effect.succeed(closeFragment(state, "text", event.id, providerMetadata(event.providerMetadata)))
|
||||
return Effect.succeed([
|
||||
LLMEvent.textEnd({ id: event.id, providerMetadata: providerMetadata(event.providerMetadata) }),
|
||||
])
|
||||
case "reasoning-start":
|
||||
return Effect.succeed(openFragment(state, "reasoning", event.id, providerMetadata(event.providerMetadata)))
|
||||
return Effect.succeed([
|
||||
LLMEvent.reasoningStart({ id: event.id, providerMetadata: providerMetadata(event.providerMetadata) }),
|
||||
])
|
||||
case "reasoning-delta":
|
||||
return Effect.succeed([
|
||||
...openFragment(state, "reasoning", event.id),
|
||||
LLMEvent.reasoningDelta({
|
||||
id: event.id,
|
||||
text: event.delta,
|
||||
@@ -776,7 +772,9 @@ function streamPartEvents(
|
||||
}),
|
||||
])
|
||||
case "reasoning-end":
|
||||
return Effect.succeed(closeFragment(state, "reasoning", event.id, providerMetadata(event.providerMetadata)))
|
||||
return Effect.succeed([
|
||||
LLMEvent.reasoningEnd({ id: event.id, providerMetadata: providerMetadata(event.providerMetadata) }),
|
||||
])
|
||||
case "tool-input-start":
|
||||
state.toolNames[event.id] = event.toolName
|
||||
return Effect.succeed([
|
||||
@@ -853,29 +851,6 @@ function streamPartEvents(
|
||||
}
|
||||
}
|
||||
|
||||
// Session persists one open text and one open reasoning fragment at a time, while AI SDK providers may overlap,
|
||||
// repeat, or omit fragment boundaries. Like the native protocol lifecycles, a start or delta for another fragment
|
||||
// closes the open one, repeated starts are ignored, and ends for fragments that are not open are dropped.
|
||||
function openFragment(state: StreamState, kind: Fragment, id: string, providerMetadata?: ProviderMetadata) {
|
||||
const open = state.open[kind]
|
||||
if (open === id) return []
|
||||
state.open[kind] = id
|
||||
const start =
|
||||
kind === "text" ? LLMEvent.textStart({ id, providerMetadata }) : LLMEvent.reasoningStart({ id, providerMetadata })
|
||||
if (open === undefined) return [start]
|
||||
return [fragmentEnd(kind, open), start]
|
||||
}
|
||||
|
||||
function closeFragment(state: StreamState, kind: Fragment, id: string, providerMetadata?: ProviderMetadata) {
|
||||
if (state.open[kind] !== id) return []
|
||||
state.open[kind] = undefined
|
||||
return [fragmentEnd(kind, id, providerMetadata)]
|
||||
}
|
||||
|
||||
function fragmentEnd(kind: Fragment, id: string, providerMetadata?: ProviderMetadata) {
|
||||
return kind === "text" ? LLMEvent.textEnd({ id, providerMetadata }) : LLMEvent.reasoningEnd({ id, providerMetadata })
|
||||
}
|
||||
|
||||
function usage(input: Extract<LanguageModelV3StreamPart, { type: "finish" }>["usage"]): UsageInput | undefined {
|
||||
const output = {
|
||||
inputTokens: input.inputTokens.total,
|
||||
|
||||
@@ -99,7 +99,7 @@ export const layer = (options?: Options) =>
|
||||
const wellknown = yield* WellKnown.Service
|
||||
const reloadLock = Semaphore.makeUnsafe(1)
|
||||
const updateLock = Semaphore.makeUnsafe(1)
|
||||
const decodeOptions = { errors: "all", onExcessProperty: "ignore", propertyOrder: "original" } as const
|
||||
const decodeOptions = { errors: "all", onExcessProperty: "ignore" } as const
|
||||
const decodeInfo = Schema.decodeUnknownOption(Info, decodeOptions)
|
||||
const parseInfo = Effect.fn("Config.parseInfo")(function* (text: string, source: string) {
|
||||
const errors: ParseError[] = []
|
||||
@@ -330,7 +330,8 @@ export const layer = (options?: Options) =>
|
||||
function* (patch: Patch) {
|
||||
const directory = initial.global ?? AbsolutePath.make(globalService.config)
|
||||
const candidates = ConfigDiscovery.names.map((name) => path.join(directory, name))
|
||||
const filepath = (yield* Effect.filter(candidates, fs.isFile)).at(-1) ?? path.join(directory, "opencode.jsonc")
|
||||
const filepath =
|
||||
(yield* Effect.filter(candidates, fs.isFile)).at(-1) ?? path.join(directory, "opencode.jsonc")
|
||||
const text = (yield* fs.readFileStringSafe(filepath)) ?? "{}\n"
|
||||
const updated = yield* Effect.try({
|
||||
try: () =>
|
||||
|
||||
@@ -42,7 +42,7 @@ export type Result =
|
||||
}
|
||||
| { readonly type: "rejected"; readonly diagnostics: readonly Diagnostic[] }
|
||||
|
||||
const options = { errors: "all", onExcessProperty: "ignore", propertyOrder: "original" } as const
|
||||
const options = { errors: "all", onExcessProperty: "ignore" } as const
|
||||
const unsupportedTopLevel = ["logLevel", "server", "subagent_depth", "layout"] as const
|
||||
const unsupportedExperimental = [
|
||||
"disable_paste_summary",
|
||||
|
||||
@@ -196,11 +196,11 @@ function decode(file: { directory: string; filepath: string; primary: boolean },
|
||||
const agent = legacy
|
||||
? Option.getOrUndefined(
|
||||
Option.map(
|
||||
decodeLegacyAgent({ name, ...markdown.data, prompt: body }, { errors: "all", propertyOrder: "original" }),
|
||||
decodeLegacyAgent({ name, ...markdown.data, prompt: body }, { errors: "all" }),
|
||||
ConfigMigrateV1.migrateAgent,
|
||||
),
|
||||
)
|
||||
: Option.getOrUndefined(decodeAgent({ ...data, system: body }, { errors: "all", propertyOrder: "original" }))
|
||||
: Option.getOrUndefined(decodeAgent({ ...data, system: body }, { errors: "all" }))
|
||||
if (!agent) return
|
||||
const info = Option.getOrUndefined(
|
||||
decodeConfig({
|
||||
|
||||
-2
@@ -46,7 +46,6 @@ import m43 from "./migration/20260812213948_worktree.js"
|
||||
import m44 from "./migration/20260819222447_session_viewed_state.js"
|
||||
import m45 from "./migration/20260823191254_nullable_workspace_binding.js"
|
||||
import m46 from "./migration/20260910120000_clear_v1_session_permission.js"
|
||||
import m47 from "./migration/20260923013825_project_time_active.js"
|
||||
|
||||
export const migrations = [
|
||||
m00,
|
||||
@@ -96,5 +95,4 @@ export const migrations = [
|
||||
m44,
|
||||
m45,
|
||||
m46,
|
||||
m47,
|
||||
] satisfies DatabaseMigration.Migration[]
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Effect } from "effect"
|
||||
import type { DatabaseMigration } from "../migration.js"
|
||||
|
||||
const migration: DatabaseMigration.Migration = {
|
||||
id: "20260923013825_project_time_active",
|
||||
up(tx) {
|
||||
return Effect.gen(function* () {
|
||||
yield* tx.run(`ALTER TABLE \`project\` ADD \`time_active\` integer DEFAULT 0 NOT NULL;`)
|
||||
yield* tx.run(`UPDATE \`project\` SET \`time_active\` = \`time_updated\`;`)
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default migration
|
||||
@@ -110,7 +110,6 @@ const schema: Omit<DatabaseMigration.Migration, "id"> = {
|
||||
\`time_created\` integer NOT NULL,
|
||||
\`time_updated\` integer NOT NULL,
|
||||
\`time_initialized\` integer,
|
||||
\`time_active\` integer DEFAULT 0 NOT NULL,
|
||||
\`sandboxes\` text NOT NULL,
|
||||
\`commands\` text
|
||||
);
|
||||
|
||||
@@ -523,8 +523,8 @@ export function run(options: Options = {}): Effect.Effect<RunResult, never, Data
|
||||
if (!(yield* hasLegacySessions(db))) return { status: "completed" as const }
|
||||
const now = Date.now()
|
||||
yield* db.run(sql`
|
||||
INSERT OR IGNORE INTO project (id, worktree, time_created, time_updated, time_active, sandboxes)
|
||||
VALUES (${Project.ID.global}, ${path.parse(global.data).root}, ${now}, ${now}, ${now}, '[]')
|
||||
INSERT OR IGNORE INTO project (id, worktree, time_created, time_updated, sandboxes)
|
||||
VALUES (${Project.ID.global}, ${path.parse(global.data).root}, ${now}, ${now}, '[]')
|
||||
`)
|
||||
if (state === undefined)
|
||||
yield* db
|
||||
@@ -753,11 +753,11 @@ function importNextDatabase(
|
||||
yield* tx.run(sql`
|
||||
INSERT OR IGNORE INTO project (
|
||||
id, worktree, vcs, name, icon_url, icon_url_override, icon_color,
|
||||
time_created, time_updated, time_initialized, time_active, sandboxes, commands
|
||||
time_created, time_updated, time_initialized, sandboxes, commands
|
||||
) VALUES (
|
||||
${project.id}, ${project.worktree}, ${project.vcs}, ${project.name}, ${project.icon_url},
|
||||
${project.icon_url_override}, ${project.icon_color}, ${project.time_created}, ${project.time_updated},
|
||||
${project.time_initialized}, ${project.time_updated}, ${project.sandboxes}, ${project.commands}
|
||||
${project.time_initialized}, ${project.sandboxes}, ${project.commands}
|
||||
)
|
||||
`)
|
||||
const existing = yield* tx
|
||||
|
||||
@@ -48,10 +48,9 @@ const proxy = (value: string, environment: Environment = process.env) => {
|
||||
)
|
||||
}
|
||||
|
||||
const constructorOptions = (input: string | Array<string> | undefined): WebSocketOptions => {
|
||||
const constructorOptions = (input: Socket.WebSocketConstructorOptions | undefined): WebSocketOptions => {
|
||||
if (typeof input === "string" || Array.isArray(input)) return { protocols: input }
|
||||
// AI routes pass handshake options through Effect's browser-shaped constructor.
|
||||
return (input ?? {}) as WebSocketOptions
|
||||
return { headers: input?.headers === undefined ? undefined : Headers.fromInput(input.headers) }
|
||||
}
|
||||
|
||||
const proxyAgent = (url: string, selectedProxy: string | undefined) => {
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
export * as LocationLifecycle from "./location-lifecycle.js"
|
||||
|
||||
import { Context, Effect, Layer, Schema } from "effect"
|
||||
import { Context, Effect, Layer } from "effect"
|
||||
import { makeLocationNode } from "@opencode/util/effect/app-node"
|
||||
import { LocationEvent } from "@opencode/schema/location-event"
|
||||
import { Bus } from "./bus.js"
|
||||
import { Form } from "./form.js"
|
||||
import { Location } from "./location.js"
|
||||
import { LocationServiceMap } from "./location-service-map.js"
|
||||
import { Permission } from "./permission.js"
|
||||
import { Project } from "./project.js"
|
||||
import { Rpc } from "./rpc.js"
|
||||
import { SessionEvent } from "./session/event.js"
|
||||
|
||||
const isSessionEvent = Schema.is(SessionEvent.Durable)
|
||||
|
||||
export class Service extends Context.Service<
|
||||
Service,
|
||||
@@ -27,17 +22,6 @@ const layer = Layer.effect(
|
||||
const permission = yield* Permission.Service
|
||||
const forms = yield* Form.Service
|
||||
const rpc = yield* Rpc.Service
|
||||
const project = yield* Project.Service
|
||||
const scope = yield* Effect.scope
|
||||
yield* project.activate(location.project.id)
|
||||
const unsubscribe = yield* bus.listen((event) => {
|
||||
if (!isSessionEvent(event) || !event.location) return Effect.void
|
||||
const ref = LocationServiceMap.canonical(event.location)
|
||||
if (ref.directory !== location.directory || ref.workspaceID !== location.workspaceID) return Effect.void
|
||||
// Listeners run inside publish; keep the write and its Project event off that path.
|
||||
return project.activate(location.project.id).pipe(Effect.forkIn(scope), Effect.asVoid)
|
||||
})
|
||||
yield* Effect.addFinalizer(() => unsubscribe)
|
||||
let closed = false
|
||||
const shutdown = yield* Effect.cached(
|
||||
Effect.gen(function* () {
|
||||
@@ -64,5 +48,5 @@ const layer = Layer.effect(
|
||||
export const node = makeLocationNode({
|
||||
service: Service,
|
||||
layer,
|
||||
deps: [Bus.node, Location.node, Permission.node, Project.node, Form.node, Rpc.node],
|
||||
deps: [Bus.node, Location.node, Permission.node, Form.node, Rpc.node],
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@ export * as Project from "./project.js"
|
||||
|
||||
import { Context, Effect, Layer, Schema } from "effect"
|
||||
import { ChildProcess } from "effect/unstable/process"
|
||||
import { and, asc, desc, eq, gte, isNull, lte, sql } from "drizzle-orm"
|
||||
import { and, asc, desc, eq, gte, isNull, lte } from "drizzle-orm"
|
||||
import path from "path"
|
||||
import { AbsolutePath } from "./schema.js"
|
||||
import { Bus } from "./bus.js"
|
||||
@@ -57,13 +57,9 @@ export const root = Effect.fn("Project.root")(function* (
|
||||
)
|
||||
})
|
||||
|
||||
const ACTIVATE_INTERVAL = 60_000
|
||||
|
||||
export interface Interface {
|
||||
readonly list: () => Effect.Effect<ReadonlyArray<Info>>
|
||||
readonly update: (input: UpdateInput) => Effect.Effect<Info, NotFoundError>
|
||||
/** Records Project activity for recency ordering, at most once per minute per Project. */
|
||||
readonly activate: (projectID: ID) => Effect.Effect<void>
|
||||
/** Resolves and persists the owning Project. */
|
||||
readonly resolve: (input: AbsolutePath, options?: { readonly discovery?: boolean }) => Effect.Effect<Resolved>
|
||||
}
|
||||
@@ -89,7 +85,6 @@ function fromRow(row: typeof ProjectTable.$inferSelect): Info {
|
||||
time: {
|
||||
created: row.time_created,
|
||||
updated: row.time_updated,
|
||||
active: row.time_active,
|
||||
},
|
||||
sandboxes: row.sandboxes,
|
||||
}
|
||||
@@ -206,7 +201,7 @@ const layer = Layer.effect(
|
||||
const rows = yield* db
|
||||
.select()
|
||||
.from(ProjectTable)
|
||||
.orderBy(desc(ProjectTable.time_active), asc(ProjectTable.id))
|
||||
.orderBy(desc(ProjectTable.time_updated), asc(ProjectTable.id))
|
||||
.all()
|
||||
.pipe(Effect.orDie)
|
||||
return rows.map(fromRow)
|
||||
@@ -238,22 +233,6 @@ const layer = Layer.effect(
|
||||
return project
|
||||
})
|
||||
|
||||
const activated = new Map<ID, number>()
|
||||
const activate = Effect.fn("Project.activate")(function* (projectID: ID) {
|
||||
const now = Date.now()
|
||||
if (now - (activated.get(projectID) ?? 0) < ACTIVATE_INTERVAL) return
|
||||
activated.set(projectID, now)
|
||||
const row = yield* db
|
||||
.update(ProjectTable)
|
||||
// Activity is not a metadata edit, so keep time_updated out of the implicit bump.
|
||||
.set({ time_active: now, time_updated: sql`${ProjectTable.time_updated}` })
|
||||
.where(eq(ProjectTable.id, projectID))
|
||||
.returning()
|
||||
.get()
|
||||
.pipe(Effect.orDie)
|
||||
if (row) yield* bus.publish(ProjectSchema.Event.Updated, fromRow(row))
|
||||
})
|
||||
|
||||
const cached = Effect.fnUntraced(function* (dir: string) {
|
||||
return yield* fs.readFileString(path.join(dir, "opencode")).pipe(
|
||||
Effect.map((value) => value.trim()),
|
||||
@@ -382,7 +361,7 @@ const layer = Layer.effect(
|
||||
})
|
||||
})
|
||||
|
||||
return Service.of({ list, update, activate, resolve })
|
||||
return Service.of({ list, update, resolve })
|
||||
}),
|
||||
)
|
||||
|
||||
|
||||
@@ -19,10 +19,6 @@ export const ProjectTable = sqliteTable("project", {
|
||||
icon_color: text(),
|
||||
...Timestamps,
|
||||
time_initialized: integer(),
|
||||
time_active: integer()
|
||||
.notNull()
|
||||
.default(0)
|
||||
.$defaultFn(() => Date.now()),
|
||||
sandboxes: absoluteArrayColumn().notNull(),
|
||||
commands: text({ mode: "json" }).$type<{ start?: string }>(),
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { ToolDefinition } from "@opencode/ai"
|
||||
import { Tool } from "@opencode/schema/tool"
|
||||
import type { StandardJSONSchemaV1, StandardSchemaV1 } from "@standard-schema/spec"
|
||||
import { Cache, Effect, JsonSchema, Schema, SchemaIssue, SchemaRepresentation } from "effect"
|
||||
import { Cache, Effect, JsonPointer, JsonSchema, Schema, SchemaIssue, SchemaRepresentation } from "effect"
|
||||
import { $ZodType, toJSONSchema } from "zod/v4/core"
|
||||
|
||||
const formatEffectIssues = SchemaIssue.makeFormatterStandardSchemaV1()
|
||||
@@ -155,7 +155,24 @@ const validateStandard = (
|
||||
const inputJsonSchema = (schema: Tool.ValueSchema<any>): JsonSchema.JsonSchema => {
|
||||
if (schema === undefined || schema === null) return {}
|
||||
if (isStandardSchema(schema)) return standardJsonSchema(schema, "input")
|
||||
return Schema.isSchema(schema) ? toJsonSchema(schema) : schema
|
||||
if (!Schema.isSchema(schema)) return schema
|
||||
const json = toJsonSchema(schema)
|
||||
// Empty Effect structs describe non-null values, but tool parameters must be
|
||||
// objects. Normalize after inlining named schemas, retaining their metadata.
|
||||
if (
|
||||
schema.ast._tag === "Objects" &&
|
||||
schema.ast.propertySignatures.length === 0 &&
|
||||
schema.ast.indexSignatures.length === 0 &&
|
||||
schema.ast.encoding === undefined &&
|
||||
schema.ast.checks === undefined &&
|
||||
isRecord(json.not) &&
|
||||
json.not.type === "null" &&
|
||||
Object.keys(json.not).length === 1
|
||||
) {
|
||||
const { not: _, ...metadata } = json
|
||||
return { ...metadata, type: "object", properties: {}, additionalProperties: false }
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
||||
const outputJsonSchema = (schema: Tool.ValueSchema<any>): JsonSchema.JsonSchema => {
|
||||
@@ -170,7 +187,7 @@ const standardJsonSchema = (schema: StandardSchemaV1<any, any>, io: "input" | "o
|
||||
}
|
||||
|
||||
const toJsonSchema = (schema: Schema.Top): JsonSchema.JsonSchema => {
|
||||
const document = Schema.toJsonSchemaDocument(schema)
|
||||
const document = Schema.toJsonSchemaDocument(schema, { onExcessProperty: "error" })
|
||||
// Effect emits valid JSON Schema that some inference providers handle poorly. Simplify it
|
||||
// without changing validation: `{ type: "integer", allOf: [{ minimum: 0 }] }` becomes
|
||||
// `{ type: "integer", minimum: 0 }` only when no keyword would be overwritten. Named schemas
|
||||
@@ -220,8 +237,8 @@ const inlineLocalReferences = (
|
||||
|
||||
const localDefinitions = definitions ?? (isRecord(value.$defs) ? value.$defs : undefined)
|
||||
if (typeof value.$ref === "string" && localDefinitions) {
|
||||
const segment = value.$ref.match(/^#\/\$defs\/([^/]+)$/)?.[1]
|
||||
const name = segment?.replaceAll("~1", "/").replaceAll("~0", "~")
|
||||
const tokens = JsonPointer.parseUriFragment(value.$ref)
|
||||
const name = tokens?.length === 2 && tokens[0] === "$defs" ? tokens[1] : undefined
|
||||
if (name && !seen.has(name)) {
|
||||
const target = localDefinitions[name]
|
||||
if (target) {
|
||||
|
||||
@@ -6,16 +6,15 @@ const decode = Schema.decodeUnknownOption(
|
||||
Schema.Struct({
|
||||
name: Schema.optional(Schema.String),
|
||||
_tag: Schema.optional(Schema.String),
|
||||
message: Schema.optional(Schema.String),
|
||||
code: Schema.optional(Schema.Union([Schema.String, Schema.Number])),
|
||||
errno: Schema.optional(Schema.Number),
|
||||
cause: Schema.optional(Schema.Unknown),
|
||||
}),
|
||||
)
|
||||
|
||||
/** Stacks are omitted; each entry keeps the classification and message of one error in the cause chain. */
|
||||
/** Error messages, stacks and SQL parameters may contain credentials. Retain only diagnostic classifications. */
|
||||
export function from(error: unknown) {
|
||||
const errors: { type: string; message?: string; code?: string | number; errno?: number }[] = []
|
||||
const errors: { type: string; code?: string | number; errno?: number }[] = []
|
||||
const seen = new Set<unknown>()
|
||||
while (error && !seen.has(error) && errors.length < 8) {
|
||||
seen.add(error)
|
||||
@@ -23,7 +22,6 @@ export function from(error: unknown) {
|
||||
if (Option.isNone(result)) break
|
||||
errors.push({
|
||||
type: result.value._tag ?? (error instanceof Error ? error.name : result.value.name) ?? "unknown",
|
||||
message: result.value.message || undefined,
|
||||
code: result.value.code,
|
||||
errno: result.value.errno,
|
||||
})
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ConfigProviderOptionsV1 } from "./provider-options.js"
|
||||
import { Provider } from "../../provider.js"
|
||||
import { Model } from "../../model.js"
|
||||
|
||||
const decodeOptions = { errors: "all", onExcessProperty: "ignore", propertyOrder: "original" } as const
|
||||
const decodeOptions = { errors: "all", onExcessProperty: "ignore" } as const
|
||||
const decodeInfo = Schema.decodeUnknownSync(Schema.fromJsonString(Info), decodeOptions)
|
||||
const encodeInfo = Schema.encodeSync(Info)
|
||||
const decodeAgent = Schema.decodeUnknownSync(Schema.fromJsonString(ConfigAgent.Info), decodeOptions)
|
||||
|
||||
@@ -11,9 +11,8 @@ export type Object = Schema.Schema.Type<typeof Object>
|
||||
export const Rule = Schema.Union([Action, Object]).annotate({ identifier: "PermissionRuleConfig" })
|
||||
export type Rule = Schema.Schema.Type<typeof Rule>
|
||||
|
||||
// Known permission keys get explicit types in the Effect schema for generated
|
||||
// docs/types. Runtime config parsing uses Effect's `propertyOrder: "original"`
|
||||
// parse option so user key order is preserved for permission precedence.
|
||||
// Known permission keys get explicit types in the Effect schema for generated docs/types.
|
||||
// StructWithRest also accepts custom permission names.
|
||||
const InputObject = Schema.StructWithRest(
|
||||
Schema.Struct({
|
||||
read: Schema.optional(Rule),
|
||||
|
||||
@@ -385,90 +385,6 @@ it.effect("routes AI Gateway model options by upstream prefix", () =>
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("closes the open AI SDK reasoning part when the next one starts", () =>
|
||||
Effect.gen(function* () {
|
||||
// AI SDK OpenAI Responses can start summary part 1 before part 0 ends, then end both at item completion (#50662).
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* aisdk.hook.sdk((event) => {
|
||||
event.sdk = {
|
||||
languageModel: () =>
|
||||
streamModel([
|
||||
{ type: "reasoning-start", id: "rs_1:0", providerMetadata: { gateway: { generationId: "gen_1" } } },
|
||||
{ type: "reasoning-start", id: "rs_1:1" },
|
||||
{ type: "reasoning-delta", id: "rs_1:1", delta: "Second summary" },
|
||||
{ type: "reasoning-end", id: "rs_1:0", providerMetadata: { gateway: { encrypted: "late" } } },
|
||||
{ type: "reasoning-end", id: "rs_1:1", providerMetadata: { gateway: { encrypted: "final" } } },
|
||||
{ type: "finish", finishReason: { unified: "stop", raw: "stop" }, usage },
|
||||
]),
|
||||
}
|
||||
})
|
||||
|
||||
const resolved = yield* aisdk.model(model("@ai-sdk/gateway"))
|
||||
const response = yield* LLMClient.generate(LLM.request({ model: resolved, prompt: "Think" })).pipe(
|
||||
Effect.provide(client),
|
||||
)
|
||||
|
||||
expect(response.events.filter((event) => event.type.startsWith("reasoning-"))).toEqual([
|
||||
{ type: "reasoning-start", id: "rs_1:0", providerMetadata: { gateway: { generationId: "gen_1" } } },
|
||||
{ type: "reasoning-end", id: "rs_1:0" },
|
||||
{ type: "reasoning-start", id: "rs_1:1", providerMetadata: undefined },
|
||||
{ type: "reasoning-delta", id: "rs_1:1", text: "Second summary", providerMetadata: undefined },
|
||||
{ type: "reasoning-end", id: "rs_1:1", providerMetadata: { gateway: { encrypted: "final" } } },
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("normalizes repeated, reopened, and overlapping AI SDK fragment boundaries", () =>
|
||||
Effect.gen(function* () {
|
||||
const aisdk = yield* AISDK.Service
|
||||
yield* aisdk.hook.sdk((event) => {
|
||||
event.sdk = {
|
||||
languageModel: () =>
|
||||
streamModel([
|
||||
// Older xAI Responses repeat the start for every summary part.
|
||||
{ type: "reasoning-start", id: "rs_1" },
|
||||
{ type: "reasoning-start", id: "rs_1" },
|
||||
{ type: "reasoning-delta", id: "rs_1", delta: "First" },
|
||||
{ type: "reasoning-end", id: "rs_1" },
|
||||
// xAI Chat keeps streaming an ended reasoning id after an empty tool_calls chunk.
|
||||
{ type: "reasoning-delta", id: "rs_1", delta: "Second" },
|
||||
{ type: "reasoning-end", id: "rs_1" },
|
||||
// xAI Responses ends every message item only when the stream flushes.
|
||||
{ type: "text-start", id: "msg_1" },
|
||||
{ type: "text-delta", id: "msg_1", delta: "One" },
|
||||
{ type: "text-start", id: "msg_2" },
|
||||
{ type: "text-delta", id: "msg_2", delta: "Two" },
|
||||
{ type: "text-end", id: "msg_1" },
|
||||
{ type: "text-end", id: "msg_2" },
|
||||
{ type: "finish", finishReason: { unified: "stop", raw: "stop" }, usage },
|
||||
]),
|
||||
}
|
||||
})
|
||||
|
||||
const resolved = yield* aisdk.model(model("@ai-sdk/gateway"))
|
||||
const response = yield* LLMClient.generate(LLM.request({ model: resolved, prompt: "Think" })).pipe(
|
||||
Effect.provide(client),
|
||||
)
|
||||
|
||||
expect(
|
||||
response.events.filter((event) => event.type.startsWith("reasoning-") || event.type.startsWith("text-")),
|
||||
).toMatchObject([
|
||||
{ type: "reasoning-start", id: "rs_1" },
|
||||
{ type: "reasoning-delta", id: "rs_1", text: "First" },
|
||||
{ type: "reasoning-end", id: "rs_1" },
|
||||
{ type: "reasoning-start", id: "rs_1" },
|
||||
{ type: "reasoning-delta", id: "rs_1", text: "Second" },
|
||||
{ type: "reasoning-end", id: "rs_1" },
|
||||
{ type: "text-start", id: "msg_1" },
|
||||
{ type: "text-delta", id: "msg_1", text: "One" },
|
||||
{ type: "text-end", id: "msg_1" },
|
||||
{ type: "text-start", id: "msg_2" },
|
||||
{ type: "text-delta", id: "msg_2", text: "Two" },
|
||||
{ type: "text-end", id: "msg_2" },
|
||||
])
|
||||
}),
|
||||
)
|
||||
|
||||
it.effect("projects replay metadata onto AI SDK prompt parts", () =>
|
||||
Effect.gen(function* () {
|
||||
const aisdk = yield* AISDK.Service
|
||||
|
||||
@@ -2,7 +2,7 @@ import path from "path"
|
||||
import fs from "fs/promises"
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Effect, Fiber, Layer, Logger, Schema, Stream } from "effect"
|
||||
import { FastCheck } from "effect/testing"
|
||||
import { Arbitrary } from "effect/unstable/arbitrary"
|
||||
import { Config } from "@opencode/core/config"
|
||||
import { Directory, Document, Event, Info } from "@opencode/schema/config"
|
||||
import { ConfigModel } from "@opencode/schema/config/model"
|
||||
@@ -632,17 +632,22 @@ describe("Config", () => {
|
||||
})
|
||||
|
||||
test("migrates arbitrary v1 configuration into valid v2 configuration", () => {
|
||||
FastCheck.assert(
|
||||
FastCheck.property(Schema.toArbitrary(ConfigV1.Info)(FastCheck), (info) => {
|
||||
const parsed = Schema.decodeUnknownSync(ConfigV1.Info)(
|
||||
Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Unknown))(
|
||||
Schema.encodeUnknownSync(Schema.fromJsonString(Schema.Unknown))(info),
|
||||
),
|
||||
)
|
||||
Schema.decodeUnknownSync(Info)(ConfigMigrateV1.migrate(parsed), { errors: "all" })
|
||||
}),
|
||||
{ numRuns: 100 },
|
||||
const result = Effect.runSync(
|
||||
Arbitrary.checkEffect(
|
||||
Arbitrary.schema(ConfigV1.Info),
|
||||
(info) => {
|
||||
const parsed = Schema.decodeUnknownSync(ConfigV1.Info)(
|
||||
Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Unknown))(
|
||||
Schema.encodeUnknownSync(Schema.fromJsonString(Schema.Unknown))(info),
|
||||
),
|
||||
)
|
||||
Schema.decodeUnknownSync(Info)(ConfigMigrateV1.migrate(parsed), { errors: "all" })
|
||||
return true
|
||||
},
|
||||
{ runs: 100 },
|
||||
),
|
||||
)
|
||||
expect(Arbitrary.formatCheckFailure(result)).toBeUndefined()
|
||||
}, 30_000)
|
||||
|
||||
test("migrates the v1 experimental subagent depth", () => {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Duration, Schema } from "effect"
|
||||
import { FastCheck } from "effect/testing"
|
||||
import { Duration, Effect, Schema } from "effect"
|
||||
import { Arbitrary } from "effect/unstable/arbitrary"
|
||||
import { ConfigNormalize } from "@opencode/core/config/normalize"
|
||||
import { Info } from "@opencode/schema/config"
|
||||
|
||||
const options = { errors: "all", onExcessProperty: "ignore", propertyOrder: "original" } as const
|
||||
const options = { errors: "all", onExcessProperty: "ignore" } as const
|
||||
|
||||
function normalized(input: unknown) {
|
||||
const result = ConfigNormalize.normalize(input)
|
||||
@@ -80,16 +80,21 @@ describe("ConfigNormalize", () => {
|
||||
})
|
||||
|
||||
test("preserves arbitrary JSON-round-tripped native configuration", () => {
|
||||
FastCheck.assert(
|
||||
FastCheck.property(Schema.toArbitrary(Info)(FastCheck), (info) => {
|
||||
const source = JSON.parse(JSON.stringify(Schema.encodeSync(Info)(info)))
|
||||
const result = normalized(source)
|
||||
expect(Schema.decodeUnknownSync(Info)(result.encoded)).toEqual(
|
||||
Schema.decodeUnknownSync(Info)(withoutEmptyCompatibilityContainers(source)),
|
||||
)
|
||||
}),
|
||||
{ numRuns: 100 },
|
||||
const result = Effect.runSync(
|
||||
Arbitrary.checkEffect(
|
||||
Arbitrary.schema(Info),
|
||||
(info) => {
|
||||
const source = JSON.parse(JSON.stringify(Schema.encodeSync(Info)(info)))
|
||||
const result = normalized(source)
|
||||
expect(Schema.decodeUnknownSync(Info)(result.encoded)).toEqual(
|
||||
Schema.decodeUnknownSync(Info)(withoutEmptyCompatibilityContainers(source)),
|
||||
)
|
||||
return true
|
||||
},
|
||||
{ runs: 100 },
|
||||
),
|
||||
)
|
||||
expect(Arbitrary.formatCheckFailure(result)).toBeUndefined()
|
||||
})
|
||||
|
||||
test("merges named maps by entry and gives valid native entries precedence", () => {
|
||||
|
||||
@@ -100,7 +100,6 @@ describe("node build", () => {
|
||||
return Project.Service.of({
|
||||
list: () => Effect.succeed([]),
|
||||
update: () => Effect.die("not implemented"),
|
||||
activate: () => Effect.void,
|
||||
resolve: (directory) => Effect.succeed({ id: Project.ID.global, directory, canonical: directory }),
|
||||
})
|
||||
}),
|
||||
|
||||
@@ -13,7 +13,6 @@ export const globalProjectNode = makeGlobalNode({
|
||||
return Project.Service.of({
|
||||
list: () => Effect.succeed([]),
|
||||
update: () => Effect.die("not implemented"),
|
||||
activate: () => Effect.void,
|
||||
resolve: (directory) => {
|
||||
const project = { id: Project.ID.global, directory, canonical: directory }
|
||||
return upsertProject(database.db, project).pipe(Effect.orDie, Effect.as(project))
|
||||
|
||||
@@ -14,7 +14,6 @@ const projectLayer = Layer.succeed(
|
||||
Project.Service.of({
|
||||
list: () => Effect.succeed([]),
|
||||
update: () => Effect.die("not implemented"),
|
||||
activate: () => Effect.void,
|
||||
resolve: () =>
|
||||
Effect.succeed({
|
||||
id: Project.ID.make("project"),
|
||||
|
||||
@@ -18,7 +18,7 @@ import { testEffect } from "./lib/effect"
|
||||
const it = testEffect(AppNodeBuilder.build(LayerNode.group([Project.node, Database.node, Bus.node])))
|
||||
|
||||
describe("Project.list", () => {
|
||||
it.effect("returns complete projects ordered by recent activity", () =>
|
||||
it.effect("returns complete projects ordered by recent update", () =>
|
||||
Effect.gen(function* () {
|
||||
const db = (yield* Database.Service).db
|
||||
const project = yield* Project.Service
|
||||
@@ -35,7 +35,6 @@ describe("Project.list", () => {
|
||||
sandboxes: [abs("/older/sandbox")],
|
||||
time_created: 1,
|
||||
time_updated: 1,
|
||||
time_active: 4,
|
||||
},
|
||||
{
|
||||
id: Project.ID.make("newer"),
|
||||
@@ -44,12 +43,17 @@ describe("Project.list", () => {
|
||||
time_created: 2,
|
||||
time_updated: 2,
|
||||
time_initialized: 3,
|
||||
time_active: 3,
|
||||
},
|
||||
])
|
||||
.run()
|
||||
|
||||
expect(yield* project.list()).toEqual([
|
||||
{
|
||||
id: Project.ID.make("newer"),
|
||||
canonical: abs("/newer"),
|
||||
time: { created: 2, updated: 2 },
|
||||
sandboxes: [],
|
||||
},
|
||||
{
|
||||
id: Project.ID.make("older"),
|
||||
canonical: abs("/older"),
|
||||
@@ -57,15 +61,9 @@ describe("Project.list", () => {
|
||||
name: "Older",
|
||||
icon: { color: "#000000" },
|
||||
commands: { start: "bun dev" },
|
||||
time: { created: 1, updated: 1, active: 4 },
|
||||
time: { created: 1, updated: 1 },
|
||||
sandboxes: [abs("/older/sandbox")],
|
||||
},
|
||||
{
|
||||
id: Project.ID.make("newer"),
|
||||
canonical: abs("/newer"),
|
||||
time: { created: 2, updated: 2, active: 3 },
|
||||
sandboxes: [],
|
||||
},
|
||||
])
|
||||
}),
|
||||
)
|
||||
@@ -85,7 +83,6 @@ describe("Project.update", () => {
|
||||
sandboxes: [],
|
||||
time_created: 1,
|
||||
time_updated: 1,
|
||||
time_active: 1,
|
||||
})
|
||||
.run()
|
||||
|
||||
@@ -114,36 +111,13 @@ describe("Project.update", () => {
|
||||
expect((yield* project.list())[0]).toEqual({
|
||||
id,
|
||||
canonical: abs("/update"),
|
||||
time: { created: 1, updated: expect.any(Number), active: 1 },
|
||||
time: { created: 1, updated: expect.any(Number) },
|
||||
sandboxes: [],
|
||||
})
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
describe("Project.activate", () => {
|
||||
it.effect("records activity without editing metadata time and throttles repeats", () =>
|
||||
Effect.gen(function* () {
|
||||
const db = (yield* Database.Service).db
|
||||
const project = yield* Project.Service
|
||||
const id = Project.ID.make("activate")
|
||||
yield* db
|
||||
.insert(ProjectTable)
|
||||
.values({ id, worktree: abs("/activate"), sandboxes: [], time_created: 1, time_updated: 1, time_active: 1 })
|
||||
.run()
|
||||
|
||||
yield* project.activate(id)
|
||||
const first = (yield* project.list())[0]
|
||||
expect(first?.time.updated).toBe(1)
|
||||
expect(first?.time.active).toBeGreaterThan(1)
|
||||
|
||||
yield* db.update(ProjectTable).set({ time_active: 2, time_updated: 1 }).run()
|
||||
yield* project.activate(id)
|
||||
expect((yield* project.list())[0]?.time).toEqual({ created: 1, updated: 1, active: 2 })
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
function remoteID(remote: string) {
|
||||
return Project.ID.make(Hash.fast(`git-remote:${remote}`))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { State } from "@opencode/core/state"
|
||||
import { Effect } from "effect"
|
||||
import { FastCheck } from "effect/testing"
|
||||
import FastCheck from "fast-check"
|
||||
|
||||
type Operation = { multiply: number; add: number }
|
||||
type Value = { value: number; order: number[] }
|
||||
|
||||
@@ -1042,7 +1042,7 @@ describe("Tool", () => {
|
||||
value: Schema.Boolean.pipe(
|
||||
Schema.decodeTo(Schema.String, {
|
||||
decode: SchemaGetter.transform((value) => String(value)),
|
||||
encode: SchemaGetter.transformOrFail((value) =>
|
||||
encode: SchemaGetter.transformEffect((value) =>
|
||||
value === "valid"
|
||||
? Effect.succeed(true)
|
||||
: Effect.fail(new SchemaIssue.InvalidValue({ message: "invalid output" }, value)),
|
||||
|
||||
@@ -67,6 +67,62 @@ test("Effect tool schemas use exact optional keys and flatten compatible constra
|
||||
})
|
||||
})
|
||||
|
||||
test.each([
|
||||
{ name: "plain", input: Schema.Struct({}), metadata: {} },
|
||||
{
|
||||
name: "annotated",
|
||||
input: Schema.Struct({}).annotate({ identifier: "Empty Input", description: "No parameters" }),
|
||||
metadata: { description: "No parameters" },
|
||||
},
|
||||
])("empty $name Effect input structs describe callable object parameters", async ({ input, metadata }) => {
|
||||
const tool: Info = {
|
||||
name: "empty",
|
||||
description: "Empty tool",
|
||||
input,
|
||||
output: input,
|
||||
execute: (value) => Effect.succeed({ output: value }),
|
||||
}
|
||||
expect(definition(tool).inputSchema).toEqual({
|
||||
...metadata,
|
||||
type: "object",
|
||||
properties: {},
|
||||
additionalProperties: false,
|
||||
})
|
||||
expect(definition(tool).outputSchema).toEqual({ ...metadata, not: { type: "null" } })
|
||||
expect(await Effect.runPromise(execute(tool, {}, context))).toMatchObject({ output: {} })
|
||||
})
|
||||
|
||||
test("empty input normalization preserves explicit Effect overrides and raw JSON schemas", () => {
|
||||
for (const override of [{ type: "object", additionalProperties: true }, { not: { type: "null" } }]) {
|
||||
const tool: Info = {
|
||||
name: "explicit",
|
||||
description: "Explicit schema tool",
|
||||
input: override,
|
||||
execute: () => Effect.succeed({ content: "unused" }),
|
||||
}
|
||||
expect(definition(tool).inputSchema).toEqual(override)
|
||||
const checked = Schema.Struct({}).check(Schema.makeFilter(() => true, { toJsonSchema: () => override }))
|
||||
expect(definition({ ...tool, output: checked }).outputSchema).toEqual(
|
||||
definition({ ...tool, input: checked }).inputSchema,
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
test("empty input normalization leaves nested empty structs unchanged", () => {
|
||||
const tool: Info = {
|
||||
name: "nested",
|
||||
description: "Nested empty struct",
|
||||
input: Schema.Struct({ value: Schema.Struct({}) }),
|
||||
execute: () => Effect.succeed({ content: "unused" }),
|
||||
}
|
||||
expect(definition(tool).inputSchema).toEqual({
|
||||
type: "object",
|
||||
properties: { value: { not: { type: "null" } } },
|
||||
required: ["value"],
|
||||
additionalProperties: false,
|
||||
})
|
||||
})
|
||||
|
||||
test("Effect tool schemas inline named child schemas", () => {
|
||||
const Child = Schema.Struct({ value: Schema.String }).annotate({ identifier: "Child" })
|
||||
const tool: Info = {
|
||||
@@ -106,6 +162,33 @@ test("Effect tool schemas resolve escaped definition names", () => {
|
||||
expect(JSON.stringify(definition(tool).inputSchema)).not.toContain("$defs")
|
||||
})
|
||||
|
||||
test.each(["Lookup Input", "café", "A/B~C% D#E"])(
|
||||
"Effect tool schemas inline URI-encoded definition %s",
|
||||
(identifier) => {
|
||||
const child = Schema.Struct({ city: Schema.String }).annotate({ identifier })
|
||||
const tool: Info = {
|
||||
name: "encoded-reference",
|
||||
description: "Encoded reference",
|
||||
input: child,
|
||||
output: Schema.Struct({ result: child }),
|
||||
execute: () => Effect.succeed({ content: "unused" }),
|
||||
}
|
||||
const expected = {
|
||||
type: "object",
|
||||
properties: { city: { type: "string" } },
|
||||
required: ["city"],
|
||||
additionalProperties: false,
|
||||
}
|
||||
expect(definition(tool).inputSchema).toEqual(expected)
|
||||
expect(definition(tool).outputSchema).toEqual({
|
||||
type: "object",
|
||||
properties: { result: expected },
|
||||
required: ["result"],
|
||||
additionalProperties: false,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
||||
test("portable schemas validate and describe typed tools", async () => {
|
||||
const input = {
|
||||
"~standard": {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { ErrorSummary } from "../../src/util/error-summary"
|
||||
|
||||
describe("ErrorSummary", () => {
|
||||
test("keeps the message and classification of each error in the cause chain", () => {
|
||||
const root = Object.assign(new Error("connect ECONNREFUSED 127.0.0.1:443"), { code: "ECONNREFUSED", errno: -61 })
|
||||
const error = new Error("Incompatible auth server: does not support dynamic client registration", { cause: root })
|
||||
expect(ErrorSummary.from(error)).toEqual([
|
||||
{ type: "Error", message: "Incompatible auth server: does not support dynamic client registration" },
|
||||
{ type: "Error", message: "connect ECONNREFUSED 127.0.0.1:443", code: "ECONNREFUSED", errno: -61 },
|
||||
])
|
||||
})
|
||||
|
||||
test("omits the stack and empty messages", () => {
|
||||
const summary = ErrorSummary.from(new Error(""))
|
||||
expect(summary).toEqual([{ type: "Error" }])
|
||||
expect(JSON.stringify(summary)).not.toContain("stack")
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import { randomUUID } from "node:crypto"
|
||||
import { Effect, FileSystem } from "effect"
|
||||
import { ByteSize, Effect, FileSystem } from "effect"
|
||||
import { nativeT } from "../native/translations"
|
||||
|
||||
export const MAX_ATTACHMENT_BYTES = 20 * 1024 * 1024
|
||||
@@ -43,7 +43,7 @@ export function readAttachment(filePath: string, maxBytes = MAX_ATTACHMENT_BYTES
|
||||
const fs = yield* FileSystem.FileSystem
|
||||
const file = yield* fs.open(filePath, { flag: "r" })
|
||||
const info = yield* file.stat
|
||||
if (info.size > FileSystem.Size(maxBytes))
|
||||
if (info.size > ByteSize.bytes(maxBytes))
|
||||
throw new Error(nativeT("desktop.picker.error.sizeLimit", { limit: MAX_ATTACHMENT_BYTES / 1024 / 1024 }))
|
||||
|
||||
const bytes = new Uint8Array(Number(info.size))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { expect } from "bun:test"
|
||||
import { NodeSocket } from "@effect/platform-node"
|
||||
import { Deferred, Effect, Fiber, Layer, Queue, Scope, Exit } from "effect"
|
||||
import { Socket } from "effect/unstable/socket"
|
||||
import { testEffect } from "../../../../core/test/lib/effect"
|
||||
import { createAskpass } from "./askpass"
|
||||
|
||||
@@ -12,16 +13,15 @@ const request = Effect.fn("test.askpass.request")(function* (
|
||||
confirm = false,
|
||||
) {
|
||||
const socket = yield* NodeSocket.makeNet({ host: "127.0.0.1", port: Number(env.OPENCODE_SSH_ASKPASS_PORT) })
|
||||
const write = yield* socket.writer
|
||||
const writer = yield* socket.writer
|
||||
const result = { text: "" }
|
||||
yield* Effect.all(
|
||||
[
|
||||
socket
|
||||
.runString((text) => {
|
||||
result.text += text
|
||||
})
|
||||
.pipe(Effect.ignore),
|
||||
write(JSON.stringify({ token: env.OPENCODE_SSH_ASKPASS_TOKEN, text, confirm }) + "\n").pipe(Effect.ignore),
|
||||
Effect.gen(function* () {
|
||||
const pull = yield* Socket.readerString(socket)
|
||||
while (true) result.text += (yield* pull).join("")
|
||||
}).pipe(Effect.ignore),
|
||||
writer.write(JSON.stringify({ token: env.OPENCODE_SSH_ASKPASS_TOKEN, text, confirm }) + "\n").pipe(Effect.ignore),
|
||||
],
|
||||
{ concurrency: "unbounded" },
|
||||
)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { NodeSocketServer } from "@effect/platform-node"
|
||||
import { Deferred, Effect, Fiber, Schema, Semaphore } from "effect"
|
||||
import { Socket } from "effect/unstable/socket"
|
||||
import { randomUUID } from "node:crypto"
|
||||
import { SshFailure } from "./command"
|
||||
|
||||
@@ -16,23 +17,27 @@ export const createAskpass = Effect.fn("Ssh.askpass")(function* (input: {
|
||||
const pending = new Map<string, Deferred.Deferred<string>>()
|
||||
const prompts = yield* Semaphore.make(1)
|
||||
const server = yield* NodeSocketServer.make({ host: "127.0.0.1", port: 0 }).pipe(Effect.mapError(SshFailure.from))
|
||||
if (server.address._tag !== "TcpAddress") return yield* Effect.fail(new SshFailure("connection"))
|
||||
if (server.address._tag === "UnixPathAddress") return yield* Effect.fail(new SshFailure("connection"))
|
||||
|
||||
const serving = yield* server
|
||||
.run((socket) =>
|
||||
Effect.gen(function* () {
|
||||
const request = yield* Deferred.make<string, SshFailure>()
|
||||
const state = { buffer: "", received: false }
|
||||
const reader = yield* socket
|
||||
.runString((chunk) => {
|
||||
if (state.received) return Effect.fail(new SshFailure("connection"))
|
||||
state.buffer += chunk
|
||||
if (state.buffer.length > 16_384) return Effect.fail(new SshFailure("connection"))
|
||||
if (!state.buffer.includes("\n")) return Effect.void
|
||||
state.received = true
|
||||
return Deferred.succeed(request, state.buffer.trim())
|
||||
})
|
||||
.pipe(Effect.ensuring(Deferred.fail(request, new SshFailure("connection"))), Effect.forkScoped)
|
||||
const reader = yield* Effect.gen(function* () {
|
||||
const pull = yield* Socket.readerString(socket)
|
||||
while (true) {
|
||||
const chunks = yield* pull
|
||||
for (const chunk of chunks) {
|
||||
if (state.received) return yield* Effect.fail(new SshFailure("connection"))
|
||||
state.buffer += chunk
|
||||
if (state.buffer.length > 16_384) return yield* Effect.fail(new SshFailure("connection"))
|
||||
if (!state.buffer.includes("\n")) continue
|
||||
state.received = true
|
||||
yield* Deferred.succeed(request, state.buffer.trim())
|
||||
}
|
||||
}
|
||||
}).pipe(Effect.ensuring(Deferred.fail(request, new SshFailure("connection"))), Effect.forkScoped)
|
||||
const message = yield* Deferred.await(request).pipe(Effect.flatMap(Schema.decodeUnknownEffect(Request)))
|
||||
if (message.token !== token) return
|
||||
|
||||
@@ -49,8 +54,8 @@ export const createAskpass = Effect.fn("Ssh.askpass")(function* (input: {
|
||||
)
|
||||
yield* input.prompt({ id, text: message.text, confirm: message.confirm })
|
||||
const value = yield* Deferred.await(response)
|
||||
const write = yield* socket.writer
|
||||
yield* write(JSON.stringify({ value }))
|
||||
const writer = yield* socket.writer
|
||||
yield* writer.write(JSON.stringify({ value }))
|
||||
}).pipe(Effect.scoped),
|
||||
)
|
||||
.pipe(Effect.raceFirst(Fiber.join(reader).pipe(Effect.andThen(Effect.fail(new SshFailure("connection"))))))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { expect } from "bun:test"
|
||||
import { NodeServices, NodeSocketServer } from "@effect/platform-node"
|
||||
import { NodeServices } from "@effect/platform-node"
|
||||
import { Deferred, Effect, Fiber, FileSystem, Layer, Path, Stream } from "effect"
|
||||
import { FetchHttpClient } from "effect/unstable/http"
|
||||
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
|
||||
@@ -228,17 +228,18 @@ it.live(
|
||||
const path = yield* Path.Path
|
||||
const config = path.join(yield* fs.makeTempDirectoryScoped({ prefix: "ssh-handshake-test-" }), "config")
|
||||
yield* fs.writeFileString(config, "")
|
||||
const connected = yield* Deferred.make<void>()
|
||||
const closed = yield* Deferred.make<void>()
|
||||
const server = yield* NodeSocketServer.make({ host: "127.0.0.1", port: 0 })
|
||||
if (server.address._tag !== "TcpAddress") return yield* Effect.die("missing port")
|
||||
yield* server
|
||||
.run((socket) =>
|
||||
socket
|
||||
.run(() => Effect.void, { onOpen: Deferred.succeed(connected, undefined).pipe(Effect.asVoid) })
|
||||
.pipe(Effect.ensuring(Deferred.succeed(closed, undefined)), Effect.ignore),
|
||||
)
|
||||
.pipe(Effect.forkScoped({ startImmediately: true }))
|
||||
const connected = Promise.withResolvers<void>()
|
||||
const closed = Promise.withResolvers<void>()
|
||||
const server = Bun.listen({
|
||||
hostname: "127.0.0.1",
|
||||
port: 0,
|
||||
socket: {
|
||||
open: () => connected.resolve(),
|
||||
data: () => {},
|
||||
close: () => closed.resolve(),
|
||||
},
|
||||
})
|
||||
yield* Effect.addFinalizer(() => Effect.sync(() => server.stop(true)))
|
||||
const controller = yield* createSshController({
|
||||
configs: [],
|
||||
binary: "unused",
|
||||
@@ -246,15 +247,16 @@ it.live(
|
||||
save: () => Effect.die("must not save"),
|
||||
})
|
||||
yield* controller.start(
|
||||
{ id: "fixture", target: `ssh -F ${quote(config)} -p ${server.address.port} 127.0.0.1`, name: "" },
|
||||
{ id: "fixture", target: `ssh -F ${quote(config)} -p ${server.port} 127.0.0.1`, name: "" },
|
||||
1,
|
||||
)
|
||||
yield* Deferred.await(connected)
|
||||
const waiting = yield* controller.resolve("fixture").pipe(Effect.forkScoped)
|
||||
yield* Effect.promise(() => connected.promise)
|
||||
const waiting = yield* controller.resolve("fixture").pipe(Effect.forkScoped({ startImmediately: true }))
|
||||
yield* controller.disconnect("fixture")
|
||||
yield* Deferred.await(closed)
|
||||
yield* Effect.promise(() => closed.promise)
|
||||
expect(yield* Fiber.join(waiting)).toBeNull()
|
||||
expect((yield* controller.state()).servers[0]?.stage).toBe("disconnected")
|
||||
yield* controller.close
|
||||
return undefined
|
||||
}).pipe(Effect.timeout("10 seconds")),
|
||||
)
|
||||
|
||||
@@ -337,7 +337,7 @@ export const createSshController = Effect.fn("Ssh.controller")(function* (input:
|
||||
|
||||
const freePort = Effect.gen(function* () {
|
||||
const server = yield* NodeSocketServer.make({ host: "127.0.0.1", port: 0 })
|
||||
if (server.address._tag !== "TcpAddress") return yield* Effect.fail(new SshFailure("connection"))
|
||||
if (server.address._tag === "UnixPathAddress") return yield* Effect.fail(new SshFailure("connection"))
|
||||
return server.address.port
|
||||
}).pipe(Effect.scoped)
|
||||
|
||||
|
||||
@@ -111,26 +111,18 @@ Real applications often select WebSocket URLs inside domain services. Effect rep
|
||||
```ts
|
||||
import { NodeSocket } from "@effect/platform-node"
|
||||
import { it } from "@effect/vitest"
|
||||
import { Deferred, Effect, Layer } from "effect"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { Socket } from "effect/unstable/socket"
|
||||
import { HttpRecorder } from "@opencode/http-recorder"
|
||||
|
||||
const roundTrip = Effect.fn("Echo.roundTrip")(function* (url: string, message: string) {
|
||||
const socket = yield* Socket.makeWebSocket(url, { closeCodeIsError: () => false })
|
||||
const write = yield* socket.writer
|
||||
const echoed = yield* Deferred.make<string>()
|
||||
|
||||
yield* socket.runString(
|
||||
(response) => {
|
||||
return Deferred.succeed(echoed, response).pipe(
|
||||
Effect.andThen(write(new Socket.CloseEvent(1000, "done"))),
|
||||
Effect.orDie,
|
||||
)
|
||||
},
|
||||
{ onOpen: write(message).pipe(Effect.orDie) },
|
||||
)
|
||||
|
||||
return yield* Deferred.await(echoed)
|
||||
const socket = yield* Socket.makeWebSocket(url)
|
||||
const writer = yield* socket.writer
|
||||
const pull = yield* Socket.readerString(socket)
|
||||
yield* writer.write(message)
|
||||
const [echoed] = yield* pull
|
||||
yield* writer.write(new Socket.CloseEvent(1000, "done"))
|
||||
return echoed
|
||||
})
|
||||
|
||||
it.effect("round trips a message", () =>
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"typescript": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"@effect/platform-node-shared": "4.0.0-rc.112"
|
||||
"@effect/platform-node-shared": "4.0.0-rc.115"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"effect": "catalog:"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NodeFileSystem } from "@effect/platform-node-shared"
|
||||
import { Deferred, Effect, Exit, FiberSet, Layer, Option, Ref, Scope, Semaphore } from "effect"
|
||||
import { Deferred, Effect, Exit, Layer, Ref, Scope, Semaphore } from "effect"
|
||||
import { Socket } from "effect/unstable/socket"
|
||||
import { fileSystem, type Interface, Service } from "../cassette/store.js"
|
||||
import type { SocketRecorderOptions } from "../options.js"
|
||||
@@ -28,7 +28,7 @@ interface ActiveRecording {
|
||||
interface PendingRecordings {
|
||||
readonly promises: Set<Promise<void>>
|
||||
readonly errors: Array<unknown>
|
||||
readonly sockets: Set<globalThis.WebSocket>
|
||||
readonly sockets: Set<Socket.WebSocketLike>
|
||||
}
|
||||
type Frame = string | Uint8Array
|
||||
|
||||
@@ -134,46 +134,6 @@ const assertEvent = (actual: WebSocketEvent, expected: WebSocketEvent | undefine
|
||||
if (expected && comparable(actual, asJson) === comparable(expected, asJson)) return
|
||||
throw new Error(`WebSocket event ${index + 1}: expected ${safeText(expected)}, received ${safeText(actual)}`)
|
||||
})
|
||||
const runHandler = <A, E, R>(handler: (value: A) => Effect.Effect<unknown, E, R> | void, value: A) =>
|
||||
Effect.suspend(() => {
|
||||
const result = handler(value)
|
||||
return Effect.isEffect(result) ? Effect.asVoid(result) : Effect.void
|
||||
})
|
||||
const runReplay = <A, E, R>(
|
||||
state: ActiveReplay,
|
||||
handler: (value: A) => Effect.Effect<unknown, E, R> | void,
|
||||
decode: (event: WebSocketEvent) => A,
|
||||
onOpen: Effect.Effect<void> | undefined,
|
||||
) =>
|
||||
Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const handlers = yield* FiberSet.make<unknown, E>()
|
||||
const run = yield* FiberSet.runtime(handlers)<R>()
|
||||
if (onOpen) yield* onOpen
|
||||
const drive = Effect.gen(function* () {
|
||||
while (true) {
|
||||
const current = yield* Ref.get(state.progress)
|
||||
const event = state.interaction.events[current.position]
|
||||
if (!event) return
|
||||
if (yield* Ref.get(state.closed))
|
||||
return yield* Effect.die(
|
||||
new Error(
|
||||
`WebSocket closed with unconsumed events: used ${current.position} of ${state.interaction.events.length}`,
|
||||
),
|
||||
)
|
||||
if (event.direction === "server") {
|
||||
yield* Ref.set(state.progress, { position: current.position + 1, changed: yield* Deferred.make<void>() })
|
||||
run(runHandler(handler, decode(event)))
|
||||
continue
|
||||
}
|
||||
yield* Deferred.await(current.changed)
|
||||
}
|
||||
})
|
||||
yield* drive.pipe(Effect.raceFirst(FiberSet.join(handlers)))
|
||||
yield* FiberSet.awaitEmpty(handlers).pipe(Effect.raceFirst(FiberSet.join(handlers)))
|
||||
}),
|
||||
)
|
||||
|
||||
const makeRecordingSocket = (
|
||||
upstream: Socket.Socket,
|
||||
cassette: Interface,
|
||||
@@ -185,71 +145,95 @@ const makeRecordingSocket = (
|
||||
const active = yield* Ref.make<ActiveRecording | undefined>(undefined)
|
||||
const writeLock = yield* Semaphore.make(1)
|
||||
return Socket.make({
|
||||
runRaw: (handler, runOptions) =>
|
||||
Effect.gen(function* () {
|
||||
const state: ActiveRecording = {
|
||||
events: [],
|
||||
eventLock: yield* Semaphore.make(1),
|
||||
accepting: yield* Ref.make(true),
|
||||
opened: false,
|
||||
valid: true,
|
||||
}
|
||||
const occupied = yield* Ref.modify(active, (current) => [current !== undefined, current ?? state])
|
||||
if (occupied) return yield* Effect.die("Concurrent runs of a recorded WebSocket are not supported")
|
||||
yield* upstream
|
||||
.runRaw(
|
||||
(message) => {
|
||||
if (!Ref.getUnsafe(state.accepting)) throw new Error("WebSocket received a frame after closing")
|
||||
state.events.push(redactEvent(encodeEvent("server", message), redactor))
|
||||
return handler(message)
|
||||
},
|
||||
{
|
||||
...runOptions,
|
||||
onOpen: Effect.gen(function* () {
|
||||
state.opened = true
|
||||
if (runOptions?.onOpen) yield* runOptions.onOpen
|
||||
reader: Effect.gen(function* () {
|
||||
const state: ActiveRecording = {
|
||||
events: [],
|
||||
eventLock: yield* Semaphore.make(1),
|
||||
accepting: yield* Ref.make(true),
|
||||
opened: false,
|
||||
valid: true,
|
||||
}
|
||||
const occupied = yield* Ref.modify(active, (current) => [current !== undefined, current ?? state])
|
||||
if (occupied) return yield* Effect.die("Concurrent runs of a recorded WebSocket are not supported")
|
||||
yield* Effect.addFinalizer((exit) =>
|
||||
writeLock.withPermit(
|
||||
state.eventLock.withPermit(
|
||||
Effect.gen(function* () {
|
||||
yield* Ref.set(state.accepting, false)
|
||||
yield* Ref.set(active, undefined)
|
||||
if (!Exit.isSuccess(exit) || !state.opened || !state.valid) return
|
||||
yield* cassette
|
||||
.append(
|
||||
name,
|
||||
{
|
||||
transport: "websocket",
|
||||
events: [...state.events],
|
||||
},
|
||||
options.metadata,
|
||||
)
|
||||
.pipe(Effect.orDie)
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
const reader = yield* upstream.reader
|
||||
state.opened = true
|
||||
return {
|
||||
...reader,
|
||||
pull: reader.pull.pipe(
|
||||
Effect.tap((messages) =>
|
||||
state.eventLock.withPermit(
|
||||
Effect.sync(() => {
|
||||
if (!Ref.getUnsafe(state.accepting)) throw new Error("WebSocket received a frame after closing")
|
||||
state.events.push(...messages.map((message) => redactEvent(encodeEvent("server", message), redactor)))
|
||||
}),
|
||||
},
|
||||
)
|
||||
.pipe(
|
||||
Effect.onExit((exit) =>
|
||||
writeLock.withPermit(
|
||||
state.eventLock.withPermit(
|
||||
Effect.gen(function* () {
|
||||
yield* Ref.set(state.accepting, false)
|
||||
yield* Ref.set(active, undefined)
|
||||
if (!Exit.isSuccess(exit) || !state.opened || !state.valid) return
|
||||
yield* cassette
|
||||
.append(
|
||||
name,
|
||||
{
|
||||
transport: "websocket",
|
||||
events: [...state.events],
|
||||
},
|
||||
options.metadata,
|
||||
)
|
||||
.pipe(Effect.orDie)
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}),
|
||||
),
|
||||
Effect.tapError((error) =>
|
||||
Effect.sync(() => {
|
||||
if (error.reason._tag !== "SocketCloseError") state.valid = false
|
||||
}),
|
||||
),
|
||||
),
|
||||
}
|
||||
}),
|
||||
writer: upstream.writer.pipe(
|
||||
Effect.map(
|
||||
(write) => (message) =>
|
||||
Effect.map((writer) => {
|
||||
const write: Socket.Writer["write"] = (message) =>
|
||||
writeLock.withPermit(
|
||||
Effect.gen(function* () {
|
||||
if (Socket.isCloseEvent(message)) return yield* write(message)
|
||||
if (Socket.isCloseEvent(message)) return yield* writer.write(message)
|
||||
const state = yield* Ref.get(active)
|
||||
if (!state || !(yield* Ref.get(state.accepting)))
|
||||
return yield* Effect.die("WebSocket writer used without an active socket run")
|
||||
const event = redactEvent(encodeEvent("client", message), redactor)
|
||||
yield* state.eventLock.withPermit(Effect.sync(() => state.events.push(event)))
|
||||
return yield* write(message).pipe(Effect.onError(() => Effect.sync(() => (state.valid = false))))
|
||||
yield* state.eventLock.withPermit(
|
||||
Effect.sync(() => state.events.push(redactEvent(encodeEvent("client", message), redactor))),
|
||||
)
|
||||
return yield* writer.write(message).pipe(Effect.onError(() => Effect.sync(() => (state.valid = false))))
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
return {
|
||||
write,
|
||||
writeAll: (messages) =>
|
||||
writeLock.withPermit(
|
||||
Effect.gen(function* () {
|
||||
const state = yield* Ref.get(active)
|
||||
if (!state || !(yield* Ref.get(state.accepting)))
|
||||
return yield* Effect.die("WebSocket writer used without an active socket run")
|
||||
yield* state.eventLock.withPermit(
|
||||
Effect.sync(() =>
|
||||
state.events.push(
|
||||
...messages.map((message) => redactEvent(encodeEvent("client", message), redactor)),
|
||||
),
|
||||
),
|
||||
)
|
||||
return yield* writer
|
||||
.writeAll(messages)
|
||||
.pipe(Effect.onError(() => Effect.sync(() => (state.valid = false))))
|
||||
}),
|
||||
),
|
||||
}
|
||||
}),
|
||||
),
|
||||
})
|
||||
})
|
||||
@@ -265,70 +249,109 @@ const makeReplaySocket = (
|
||||
const active = yield* Ref.make<ActiveReplay | undefined>(undefined)
|
||||
const runLock = yield* Semaphore.make(1)
|
||||
return Socket.make({
|
||||
runRaw: (handler, runOptions) =>
|
||||
runLock
|
||||
.withPermitsIfAvailable(1)(
|
||||
Effect.gen(function* () {
|
||||
const claimed = yield* replay
|
||||
.claim((interaction) =>
|
||||
interaction ? Effect.void : Effect.die("Missing recorded WebSocket interaction"),
|
||||
)
|
||||
.pipe(Effect.orDie)
|
||||
const state = {
|
||||
interaction: claimed.interaction,
|
||||
progress: yield* Ref.make({ position: 0, changed: yield* Deferred.make<void>() }),
|
||||
writeLock: yield* Semaphore.make(1),
|
||||
closed: yield* Ref.make(false),
|
||||
}
|
||||
yield* Ref.set(active, state)
|
||||
yield* runReplay(state, handler, decodeEvent, runOptions?.onOpen).pipe(
|
||||
Effect.ensuring(Ref.set(active, undefined)),
|
||||
)
|
||||
}),
|
||||
)
|
||||
.pipe(
|
||||
Effect.flatMap(
|
||||
Option.match({
|
||||
onNone: () => Effect.die("Concurrent runs of a replayed WebSocket are not supported"),
|
||||
onSome: () => Effect.void,
|
||||
}),
|
||||
reader: Effect.gen(function* () {
|
||||
if (!(yield* runLock.takeIfAvailable(1)))
|
||||
return yield* Effect.die("Concurrent runs of a replayed WebSocket are not supported")
|
||||
yield* Effect.addFinalizer(() =>
|
||||
Effect.all([Ref.set(active, undefined), runLock.release(1)], { discard: true }),
|
||||
)
|
||||
const claimed = yield* replay
|
||||
.claim((interaction) => (interaction ? Effect.void : Effect.die("Missing recorded WebSocket interaction")))
|
||||
.pipe(Effect.orDie)
|
||||
const state = {
|
||||
interaction: claimed.interaction,
|
||||
progress: yield* Ref.make({ position: 0, changed: yield* Deferred.make<void>() }),
|
||||
writeLock: yield* Semaphore.make(1),
|
||||
closed: yield* Ref.make(false),
|
||||
}
|
||||
yield* Ref.set(active, state)
|
||||
const pull: Socket.Reader["pull"] = Effect.suspend(() =>
|
||||
Effect.gen(function* () {
|
||||
const current = yield* Ref.get(state.progress)
|
||||
if (yield* Ref.get(state.closed))
|
||||
return yield* Effect.fail(new Socket.SocketError({ reason: new Socket.SocketCloseError({ code: 1000 }) }))
|
||||
const remaining = state.interaction.events.slice(current.position)
|
||||
const client = remaining.findIndex((event) => event.direction === "client")
|
||||
const messages = client === -1 ? remaining : remaining.slice(0, client)
|
||||
if (messages.length > 0) {
|
||||
yield* Ref.set(state.progress, {
|
||||
position: current.position + messages.length,
|
||||
changed: yield* Deferred.make<void>(),
|
||||
})
|
||||
return messages.map(decodeEvent) as [Frame, ...Array<Frame>]
|
||||
}
|
||||
if (current.position === state.interaction.events.length)
|
||||
return yield* Effect.fail(new Socket.SocketError({ reason: new Socket.SocketCloseError({ code: 1000 }) }))
|
||||
yield* Deferred.await(current.changed)
|
||||
return yield* pull
|
||||
}),
|
||||
)
|
||||
return { pull, upgrade: Socket.SocketUpgradeError.unsupported }
|
||||
}),
|
||||
writer: Effect.succeed({
|
||||
write: (message) =>
|
||||
Ref.get(active).pipe(
|
||||
Effect.flatMap((state) =>
|
||||
state
|
||||
? state.writeLock.withPermit(
|
||||
Effect.gen(function* () {
|
||||
const current = yield* Ref.get(state.progress)
|
||||
if (Socket.isCloseEvent(message)) {
|
||||
yield* Ref.set(state.closed, true)
|
||||
yield* Deferred.succeed(current.changed, undefined)
|
||||
if (current.position === state.interaction.events.length) return
|
||||
return yield* Effect.die(
|
||||
new Error(
|
||||
`WebSocket closed with unconsumed events: used ${current.position} of ${state.interaction.events.length}`,
|
||||
),
|
||||
)
|
||||
}
|
||||
const actual = redactEvent(encodeEvent("client", message), redactor)
|
||||
yield* assertEvent(
|
||||
actual,
|
||||
state.interaction.events[current.position],
|
||||
current.position,
|
||||
options.compareClientMessagesAsJson === true,
|
||||
)
|
||||
yield* Ref.set(state.progress, {
|
||||
position: current.position + 1,
|
||||
changed: yield* Deferred.make<void>(),
|
||||
})
|
||||
yield* Deferred.succeed(current.changed, undefined)
|
||||
}),
|
||||
)
|
||||
: Effect.die("WebSocket writer used without an active socket run"),
|
||||
),
|
||||
),
|
||||
writer: Effect.succeed((message) =>
|
||||
Ref.get(active).pipe(
|
||||
Effect.flatMap((state) =>
|
||||
state
|
||||
? state.writeLock.withPermit(
|
||||
Effect.gen(function* () {
|
||||
const current = yield* Ref.get(state.progress)
|
||||
if (Socket.isCloseEvent(message)) {
|
||||
yield* Ref.set(state.closed, true)
|
||||
yield* Deferred.succeed(current.changed, undefined)
|
||||
if (current.position === state.interaction.events.length) return
|
||||
return yield* Effect.die(
|
||||
new Error(
|
||||
`WebSocket closed with unconsumed events: used ${current.position} of ${state.interaction.events.length}`,
|
||||
),
|
||||
writeAll: (messages) =>
|
||||
Effect.forEach(
|
||||
messages,
|
||||
(message) =>
|
||||
Ref.get(active).pipe(
|
||||
Effect.flatMap((state) =>
|
||||
state
|
||||
? state.writeLock.withPermit(
|
||||
Effect.gen(function* () {
|
||||
const current = yield* Ref.get(state.progress)
|
||||
yield* assertEvent(
|
||||
redactEvent(encodeEvent("client", message), redactor),
|
||||
state.interaction.events[current.position],
|
||||
current.position,
|
||||
options.compareClientMessagesAsJson === true,
|
||||
)
|
||||
yield* Ref.set(state.progress, {
|
||||
position: current.position + 1,
|
||||
changed: yield* Deferred.make<void>(),
|
||||
})
|
||||
yield* Deferred.succeed(current.changed, undefined)
|
||||
}),
|
||||
)
|
||||
}
|
||||
const actual = redactEvent(encodeEvent("client", message), redactor)
|
||||
yield* assertEvent(
|
||||
actual,
|
||||
state.interaction.events[current.position],
|
||||
current.position,
|
||||
options.compareClientMessagesAsJson === true,
|
||||
)
|
||||
yield* Ref.set(state.progress, {
|
||||
position: current.position + 1,
|
||||
changed: yield* Deferred.make<void>(),
|
||||
})
|
||||
yield* Deferred.succeed(current.changed, undefined)
|
||||
}),
|
||||
)
|
||||
: Effect.die("WebSocket writer used without an active socket run"),
|
||||
: Effect.die("WebSocket writer used without an active socket run"),
|
||||
),
|
||||
),
|
||||
{ discard: true },
|
||||
),
|
||||
),
|
||||
),
|
||||
}),
|
||||
})
|
||||
})
|
||||
|
||||
@@ -399,13 +422,13 @@ const makeRecordingWebSocketConstructor = (
|
||||
const onOpen = () => {
|
||||
opened = true
|
||||
}
|
||||
const onMessage = (event: MessageEvent) => {
|
||||
const onMessage = (event: Socket.WebSocketEvent) => {
|
||||
appendEvent("server", event.data)
|
||||
}
|
||||
const onError = () => {
|
||||
failed = true
|
||||
}
|
||||
const onClose = (event: CloseEvent) => {
|
||||
const onClose = (event: Socket.WebSocketEvent) => {
|
||||
native.removeEventListener("open", onOpen)
|
||||
native.removeEventListener("message", onMessage)
|
||||
native.removeEventListener("error", onError)
|
||||
@@ -421,7 +444,7 @@ const makeRecordingWebSocketConstructor = (
|
||||
sequence,
|
||||
url: request.url,
|
||||
protocols: requestedProtocols,
|
||||
close: { code: event.code, reason: event.reason },
|
||||
close: { code: event.code ?? 1006, reason: event.reason ?? "" },
|
||||
},
|
||||
events: [...events],
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { Deferred, Effect, Exit, Fiber, Layer } from "effect"
|
||||
import { Deferred, Effect, Exit, Fiber, FiberSet, Layer } from "effect"
|
||||
import { Socket } from "effect/unstable/socket"
|
||||
import { existsSync } from "node:fs"
|
||||
import { HttpRecorder } from "../src"
|
||||
@@ -7,10 +7,58 @@ import { layerSocketWithMode } from "../src/websocket/recorder"
|
||||
import { failureText, readCassette, seedCassetteDirectory, tempDirectory, withEnvironment } from "./support"
|
||||
|
||||
const unavailableSocket = Socket.make({
|
||||
runRaw: () => Effect.die(new Error("unexpected live WebSocket run")),
|
||||
writer: Effect.succeed(() => Effect.die(new Error("unexpected live WebSocket write"))),
|
||||
reader: Effect.die(new Error("unexpected live WebSocket run")),
|
||||
writer: Effect.succeed({
|
||||
write: () => Effect.die(new Error("unexpected live WebSocket write")),
|
||||
writeAll: () => Effect.die(new Error("unexpected live WebSocket write")),
|
||||
}),
|
||||
})
|
||||
|
||||
const runRaw = <E, R>(
|
||||
socket: Socket.Socket,
|
||||
handler: (message: string | Uint8Array) => Effect.Effect<unknown, E, R> | void,
|
||||
onOpen?: Effect.Effect<void, E, R>,
|
||||
) =>
|
||||
Effect.scoped(
|
||||
Effect.gen(function* () {
|
||||
const handlers = yield* FiberSet.make<unknown, E>()
|
||||
const run = yield* FiberSet.runtime(handlers)<R>()
|
||||
const reader = yield* socket.reader
|
||||
if (onOpen) yield* onOpen
|
||||
yield* Effect.gen(function* () {
|
||||
while (true) {
|
||||
const messages = yield* reader.pull
|
||||
messages.forEach((message) =>
|
||||
run(
|
||||
Effect.suspend(() => {
|
||||
const result = handler(message)
|
||||
return Effect.isEffect(result) ? Effect.asVoid(result) : Effect.void
|
||||
}),
|
||||
),
|
||||
)
|
||||
}
|
||||
}).pipe(
|
||||
Effect.catchIf(
|
||||
(error) => Socket.SocketError.is(error) && error.reason._tag === "SocketCloseError",
|
||||
() => Effect.void,
|
||||
),
|
||||
Effect.raceFirst(FiberSet.join(handlers)),
|
||||
)
|
||||
yield* FiberSet.awaitEmpty(handlers).pipe(Effect.raceFirst(FiberSet.join(handlers)))
|
||||
}),
|
||||
)
|
||||
|
||||
const runString = <E, R>(
|
||||
socket: Socket.Socket,
|
||||
handler: (message: string) => Effect.Effect<unknown, E, R> | void,
|
||||
onOpen?: Effect.Effect<void, E, R>,
|
||||
) =>
|
||||
runRaw(
|
||||
socket,
|
||||
(message) => handler(typeof message === "string" ? message : new TextDecoder().decode(message)),
|
||||
onOpen,
|
||||
)
|
||||
|
||||
class EchoWebSocket extends EventTarget {
|
||||
readonly protocol = ""
|
||||
readonly extensions = ""
|
||||
@@ -53,12 +101,13 @@ describe("WebSocket", () => {
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.makeWebSocket("wss://echo.example.test/one", {
|
||||
protocols: ["echo.v1"],
|
||||
closeCodeIsError: () => false,
|
||||
})
|
||||
const write = yield* socket.writer
|
||||
yield* socket.runString(() => write(new Socket.CloseEvent(1000, "complete")).pipe(Effect.orDie), {
|
||||
onOpen: write("hello").pipe(Effect.orDie),
|
||||
})
|
||||
const writer = yield* socket.writer
|
||||
yield* runString(
|
||||
socket,
|
||||
() => writer.write(new Socket.CloseEvent(1000, "complete")).pipe(Effect.orDie),
|
||||
writer.write("hello").pipe(Effect.orDie),
|
||||
)
|
||||
}).pipe(Effect.scoped, Effect.provide(recorder)),
|
||||
),
|
||||
)
|
||||
@@ -141,17 +190,15 @@ describe("WebSocket", () => {
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.makeWebSocket("wss://events.example.test/workspaces/one", {
|
||||
protocols: ["events.v1"],
|
||||
closeCodeIsError: () => false,
|
||||
})
|
||||
const write = yield* socket.writer
|
||||
const writer = yield* socket.writer
|
||||
const received: string[] = []
|
||||
yield* socket.runString(
|
||||
yield* runString(
|
||||
socket,
|
||||
(message) => {
|
||||
received.push(message)
|
||||
},
|
||||
{
|
||||
onOpen: write('{"type":"subscribe"}').pipe(Effect.orDie),
|
||||
},
|
||||
writer.write('{"type":"subscribe"}').pipe(Effect.orDie),
|
||||
)
|
||||
return received
|
||||
}).pipe(Effect.scoped, Effect.provide(recorder)),
|
||||
@@ -187,7 +234,7 @@ describe("WebSocket", () => {
|
||||
const exit = await Effect.runPromise(
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.makeWebSocket("wss://events.example.test/workspaces/two")
|
||||
yield* socket.runString(() => {})
|
||||
yield* runString<never, never>(socket, () => {})
|
||||
}).pipe(Effect.scoped, Effect.exit, Effect.provide(recorder)),
|
||||
)
|
||||
|
||||
@@ -200,23 +247,28 @@ describe("WebSocket", () => {
|
||||
type: "response.completed",
|
||||
token: "server-secret",
|
||||
})
|
||||
let sent = false
|
||||
const upstream = Socket.make({
|
||||
runRaw: (handler, options) =>
|
||||
Effect.gen(function* () {
|
||||
if (options?.onOpen) yield* options.onOpen
|
||||
const result = handler(response)
|
||||
if (Effect.isEffect(result)) yield* result
|
||||
reader: Effect.succeed({
|
||||
pull: Effect.suspend(() => {
|
||||
if (sent) return Effect.fail(new Socket.SocketError({ reason: new Socket.SocketCloseError({ code: 1000 }) }))
|
||||
sent = true
|
||||
return Effect.succeed([response])
|
||||
}),
|
||||
writer: Effect.succeed(() => Effect.void),
|
||||
upgrade: Socket.SocketUpgradeError.unsupported,
|
||||
}),
|
||||
writer: Effect.succeed({ write: () => Effect.void, writeAll: () => Effect.void }),
|
||||
})
|
||||
|
||||
await Effect.runPromise(
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.Socket
|
||||
const write = yield* socket.writer
|
||||
yield* socket.runRaw(() => {}, {
|
||||
onOpen: write(JSON.stringify({ type: "response.create", token: "client-secret" })).pipe(Effect.orDie),
|
||||
})
|
||||
const writer = yield* socket.writer
|
||||
yield* runRaw(
|
||||
socket,
|
||||
() => {},
|
||||
writer.write(JSON.stringify({ type: "response.create", token: "client-secret" })).pipe(Effect.orDie),
|
||||
)
|
||||
}).pipe(
|
||||
Effect.scoped,
|
||||
Effect.provide(
|
||||
@@ -279,14 +331,14 @@ describe("WebSocket", () => {
|
||||
await Effect.runPromise(
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.Socket
|
||||
const write = yield* socket.writer
|
||||
yield* socket.runRaw((message) =>
|
||||
const writer = yield* socket.writer
|
||||
yield* runRaw(socket, (message) =>
|
||||
Effect.gen(function* () {
|
||||
if (typeof message !== "string") return
|
||||
received.push(message)
|
||||
const event: unknown = JSON.parse(message)
|
||||
if (typeof event !== "object" || event === null || !("type" in event)) return
|
||||
if (event.type === "session.created") yield* write('{"prompt":"hello","type":"response.create"}')
|
||||
if (event.type === "session.created") yield* writer.write('{"prompt":"hello","type":"response.create"}')
|
||||
}),
|
||||
)
|
||||
}).pipe(
|
||||
@@ -343,21 +395,21 @@ describe("WebSocket", () => {
|
||||
await Effect.runPromise(
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.Socket
|
||||
const write = yield* socket.writer
|
||||
yield* socket.runString((message) =>
|
||||
const writer = yield* socket.writer
|
||||
yield* runString(socket, (message) =>
|
||||
Effect.gen(function* () {
|
||||
received.push(message)
|
||||
const event: unknown = JSON.parse(message)
|
||||
if (typeof event !== "object" || event === null) return
|
||||
if ("type" in event && event.type === "session.created") {
|
||||
yield* write('{"prompt":"first","type":"response.create"}')
|
||||
yield* writer.write('{"prompt":"first","type":"response.create"}')
|
||||
return
|
||||
}
|
||||
if ("id" in event && event.id === "first") {
|
||||
yield* write('{"prompt":"second","type":"response.create"}')
|
||||
yield* writer.write('{"prompt":"second","type":"response.create"}')
|
||||
return
|
||||
}
|
||||
yield* write(new Socket.CloseEvent(1000, "done"))
|
||||
yield* writer.write(new Socket.CloseEvent(1000, "done"))
|
||||
}),
|
||||
)
|
||||
}).pipe(
|
||||
@@ -393,7 +445,7 @@ describe("WebSocket", () => {
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.Socket
|
||||
const second = yield* Deferred.make<void>()
|
||||
yield* socket.runString((message) =>
|
||||
yield* runString(socket, (message) =>
|
||||
message === "first" ? Deferred.await(second) : Deferred.succeed(second, undefined),
|
||||
)
|
||||
}).pipe(
|
||||
@@ -420,23 +472,21 @@ describe("WebSocket", () => {
|
||||
const socket = yield* Socket.Socket
|
||||
const started = yield* Deferred.make<void>()
|
||||
const release = yield* Deferred.make<void>()
|
||||
const first = yield* socket
|
||||
.runString((message) =>
|
||||
Effect.gen(function* () {
|
||||
received.push(message)
|
||||
yield* Deferred.succeed(started, undefined)
|
||||
yield* Deferred.await(release)
|
||||
}),
|
||||
)
|
||||
.pipe(Effect.forkChild)
|
||||
const first = yield* runString(socket, (message) =>
|
||||
Effect.gen(function* () {
|
||||
received.push(message)
|
||||
yield* Deferred.succeed(started, undefined)
|
||||
yield* Deferred.await(release)
|
||||
}),
|
||||
).pipe(Effect.forkChild)
|
||||
yield* Deferred.await(started)
|
||||
|
||||
const concurrent = yield* Effect.exit(socket.runString(() => Effect.void))
|
||||
const concurrent = yield* Effect.exit(runString(socket, () => Effect.void))
|
||||
expect(failureText(concurrent)).toContain("Concurrent runs")
|
||||
|
||||
yield* Deferred.succeed(release, undefined)
|
||||
yield* Fiber.join(first)
|
||||
yield* socket.runString((message) => Effect.sync(() => received.push(message)))
|
||||
yield* runString(socket, (message) => Effect.sync(() => received.push(message)))
|
||||
}).pipe(
|
||||
Effect.scoped,
|
||||
Effect.provide(
|
||||
@@ -462,11 +512,9 @@ describe("WebSocket", () => {
|
||||
const exit = await Effect.runPromise(
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.Socket
|
||||
const write = yield* socket.writer
|
||||
const writer = yield* socket.writer
|
||||
return yield* Effect.exit(
|
||||
socket.runRaw(() => {}, {
|
||||
onOpen: write(new Socket.CloseEvent(1000)).pipe(Effect.orDie),
|
||||
}),
|
||||
runRaw(socket, () => {}, writer.write(new Socket.CloseEvent(1000)).pipe(Effect.orDie)),
|
||||
)
|
||||
}).pipe(
|
||||
Effect.scoped,
|
||||
@@ -486,7 +534,7 @@ describe("WebSocket", () => {
|
||||
const exit = await Effect.runPromise(
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.Socket
|
||||
return yield* Effect.exit(socket.runRaw(() => {}))
|
||||
return yield* Effect.exit(runRaw<never, never>(socket, () => {}))
|
||||
}).pipe(
|
||||
Effect.scoped,
|
||||
Effect.provide(
|
||||
@@ -495,8 +543,8 @@ describe("WebSocket", () => {
|
||||
Layer.succeed(
|
||||
Socket.Socket,
|
||||
Socket.make({
|
||||
runRaw: () => Effect.die(new Error("connection failed")),
|
||||
writer: Effect.succeed(() => Effect.void),
|
||||
reader: Effect.die(new Error("connection failed")),
|
||||
writer: Effect.succeed({ write: () => Effect.void, writeAll: () => Effect.void }),
|
||||
}),
|
||||
),
|
||||
),
|
||||
@@ -534,13 +582,14 @@ describe("WebSocket", () => {
|
||||
await Effect.runPromise(
|
||||
Effect.gen(function* () {
|
||||
const socket = yield* Socket.Socket
|
||||
const write = yield* socket.writer
|
||||
const run = socket.runRaw(
|
||||
const writer = yield* socket.writer
|
||||
const run = runRaw(
|
||||
socket,
|
||||
(message) => {
|
||||
if (typeof message === "string") throw new Error("Expected a binary WebSocket frame")
|
||||
received.push([...message])
|
||||
},
|
||||
{ onOpen: write(new Uint8Array([1, 2])).pipe(Effect.orDie) },
|
||||
writer.write(new Uint8Array([1, 2])).pipe(Effect.orDie),
|
||||
)
|
||||
yield* run
|
||||
yield* run
|
||||
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user