complete framework remediation validation

This commit is contained in:
2026-08-09 14:39:22 +05:30
parent 905cbce0c1
commit 51286d0fa3
21 changed files with 898 additions and 1474 deletions
+231 -4
View File
@@ -109,12 +109,101 @@
"name": "inter-app-api-showcase", "name": "inter-app-api-showcase",
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.0.0", "@eslint/js": "^9.0.0",
"@types/bun": "latest", "@types/bun": "^1.3.14",
"@wrnexus/cli": "0.8.6", "@wrnexus/cli": "0.8.6",
"eslint": "^9.0.0", "eslint": "^9.0.0",
"prettier": "latest", "prettier": "^3.9.6",
"typescript": "^5.5.0", "typescript": "^5.5.0",
"typescript-eslint": "latest", "typescript-eslint": "^8.65.0",
},
},
"examples/inter-app-api-showcase/apps/admin": {
"name": "admin",
"version": "0.1.0",
"dependencies": {
"@wrnexus/ai": "0.8.6",
"@wrnexus/auth": "0.8.6",
"@wrnexus/authz": "0.8.6",
"@wrnexus/captcha": "0.8.6",
"@wrnexus/core": "0.8.6",
"@wrnexus/csr": "0.8.6",
"@wrnexus/db": "0.8.6",
"@wrnexus/dev-server": "0.8.6",
"@wrnexus/encryption": "0.8.6",
"@wrnexus/helpers": "0.8.6",
"@wrnexus/i18n": "0.8.6",
"@wrnexus/image": "0.8.6",
"@wrnexus/jwt": "0.8.6",
"@wrnexus/observability": "0.8.6",
"@wrnexus/realtime": "0.8.6",
"@wrnexus/security": "0.8.6",
"@wrnexus/store": "0.8.6",
"@wrnexus/styles": "0.8.6",
"@wrnexus/tracking": "0.8.6",
"@wrnexus/ui": "0.8.6",
"@wrnexus/uploader": "0.8.6",
"@wrnexus/validation": "0.8.6",
},
"devDependencies": {
"@eslint/js": "^9.0.0",
"@iconify-json/lucide": "^1.2.118",
"@iconify/tailwind4": "^1.2.3",
"@tailwindcss/cli": "^4.0.0",
"@types/bun": "^1.3.14",
"@wrnexus/cli": "0.8.6",
"eslint": "^9.0.0",
"prettier": "^3.9.6",
"tailwindcss": "^4.0.0",
"typescript": "^5.5.0",
"typescript-eslint": "^8.65.0",
},
},
"examples/inter-app-api-showcase/apps/web": {
"name": "web",
"version": "0.1.0",
"dependencies": {
"@wrnexus/ai": "0.8.6",
"@wrnexus/auth": "0.8.6",
"@wrnexus/authz": "0.8.6",
"@wrnexus/captcha": "0.8.6",
"@wrnexus/core": "0.8.6",
"@wrnexus/csr": "0.8.6",
"@wrnexus/db": "0.8.6",
"@wrnexus/dev-server": "0.8.6",
"@wrnexus/encryption": "0.8.6",
"@wrnexus/helpers": "0.8.6",
"@wrnexus/i18n": "0.8.6",
"@wrnexus/image": "0.8.6",
"@wrnexus/jwt": "0.8.6",
"@wrnexus/observability": "0.8.6",
"@wrnexus/realtime": "0.8.6",
"@wrnexus/security": "0.8.6",
"@wrnexus/store": "0.8.6",
"@wrnexus/styles": "0.8.6",
"@wrnexus/tracking": "0.8.6",
"@wrnexus/ui": "0.8.6",
"@wrnexus/uploader": "0.8.6",
"@wrnexus/validation": "0.8.6",
},
"devDependencies": {
"@eslint/js": "^9.0.0",
"@iconify-json/lucide": "^1.2.118",
"@iconify/tailwind4": "^1.2.3",
"@tailwindcss/cli": "^4.0.0",
"@types/bun": "^1.3.14",
"@wrnexus/cli": "0.8.6",
"eslint": "^9.0.0",
"prettier": "^3.9.6",
"tailwindcss": "^4.0.0",
"typescript": "^5.5.0",
"typescript-eslint": "^8.65.0",
},
},
"examples/inter-app-api-showcase/packages/shared": {
"name": "@app/shared",
"version": "0.0.0",
"dependencies": {
"@wrnexus/pubsub": "0.8.6",
}, },
}, },
"packages/ai": { "packages/ai": {
@@ -563,7 +652,7 @@
}, },
"services/managed-captcha": { "services/managed-captcha": {
"name": "@wrnexus/managed-captcha-service", "name": "@wrnexus/managed-captcha-service",
"version": "0.8.0", "version": "0.8.6",
"dependencies": { "dependencies": {
"@wrnexus/captcha": "workspace:*", "@wrnexus/captcha": "workspace:*",
}, },
@@ -580,6 +669,8 @@
"packages": { "packages": {
"@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="], "@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="],
"@app/shared": ["@app/shared@workspace:examples/inter-app-api-showcase/packages/shared"],
"@cyberalien/svg-utils": ["@cyberalien/svg-utils@1.2.19", "", { "dependencies": { "@iconify/types": "^2.0.0" } }, "sha512-paDJoDu+LhuH5Ma1q0BDqBpg6d16Xk22cZZrlg/s/J9oB8KgnnpU/snaEETJu2G1pwYcWQINUz6WUqu0Wm9k6A=="], "@cyberalien/svg-utils": ["@cyberalien/svg-utils@1.2.19", "", { "dependencies": { "@iconify/types": "^2.0.0" } }, "sha512-paDJoDu+LhuH5Ma1q0BDqBpg6d16Xk22cZZrlg/s/J9oB8KgnnpU/snaEETJu2G1pwYcWQINUz6WUqu0Wm9k6A=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="], "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.1", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ=="],
@@ -950,6 +1041,8 @@
"acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="],
"admin": ["admin@workspace:examples/inter-app-api-showcase/apps/admin"],
"ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="], "ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
@@ -1286,6 +1379,8 @@
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
"web": ["web@workspace:examples/inter-app-api-showcase/apps/web"],
"whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="], "whatwg-mimetype": ["whatwg-mimetype@3.0.0", "", {}, "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
@@ -1318,6 +1413,12 @@
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"admin/@eslint/js": ["@eslint/js@9.39.5", "", {}, "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A=="],
"admin/eslint": ["eslint@9.39.5", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.6", "@eslint/js": "9.39.5", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw=="],
"admin/typescript-eslint": ["typescript-eslint@8.66.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.66.0", "@typescript-eslint/parser": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0", "@typescript-eslint/utils": "8.66.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-QlEbBPz/RuJ1XUHj29nm3t0F/O/cSlEnntozqPOYHnnTGAXFamnMBu5i9Vn6vhUPHGAjR+Vl+5J8vPN/BMUrJw=="],
"csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="],
"dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="],
@@ -1338,8 +1439,38 @@
"tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="], "tsyringe/tslib": ["tslib@1.14.1", "", {}, "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="],
"web/@eslint/js": ["@eslint/js@9.39.5", "", {}, "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A=="],
"web/eslint": ["eslint@9.39.5", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", "@eslint/eslintrc": "^3.3.6", "@eslint/js": "9.39.5", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.4.0", "eslint-visitor-keys": "^4.2.1", "espree": "^10.4.0", "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, "peerDependencies": { "jiti": "*" }, "optionalPeers": ["jiti"], "bin": { "eslint": "bin/eslint.js" } }, "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw=="],
"web/typescript-eslint": ["typescript-eslint@8.66.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.66.0", "@typescript-eslint/parser": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0", "@typescript-eslint/utils": "8.66.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-QlEbBPz/RuJ1XUHj29nm3t0F/O/cSlEnntozqPOYHnnTGAXFamnMBu5i9Vn6vhUPHGAjR+Vl+5J8vPN/BMUrJw=="],
"@eslint/eslintrc/espree/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], "@eslint/eslintrc/espree/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"admin/eslint/@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="],
"admin/eslint/@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
"admin/eslint/@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
"admin/eslint/@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
"admin/eslint/eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
"admin/eslint/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"admin/eslint/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"admin/eslint/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
"admin/typescript-eslint/@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.66.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.66.0", "@typescript-eslint/type-utils": "8.66.0", "@typescript-eslint/utils": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.66.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A=="],
"admin/typescript-eslint/@typescript-eslint/parser": ["@typescript-eslint/parser@8.66.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.66.0", "@typescript-eslint/types": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g=="],
"admin/typescript-eslint/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.66.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.66.0", "@typescript-eslint/tsconfig-utils": "8.66.0", "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg=="],
"admin/typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.66.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.66.0", "@typescript-eslint/types": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA=="],
"csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="],
"inter-app-api-showcase/eslint/@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="], "inter-app-api-showcase/eslint/@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="],
@@ -1366,6 +1497,58 @@
"inter-app-api-showcase/typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.66.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.66.0", "@typescript-eslint/types": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA=="], "inter-app-api-showcase/typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.66.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.66.0", "@typescript-eslint/types": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA=="],
"web/eslint/@eslint/config-array": ["@eslint/config-array@0.21.2", "", { "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", "minimatch": "^3.1.5" } }, "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw=="],
"web/eslint/@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "^0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="],
"web/eslint/@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "^7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="],
"web/eslint/@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "^0.17.0", "levn": "^0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="],
"web/eslint/eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="],
"web/eslint/eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="],
"web/eslint/espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="],
"web/eslint/minimatch": ["minimatch@3.1.5", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w=="],
"web/typescript-eslint/@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.66.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.66.0", "@typescript-eslint/type-utils": "8.66.0", "@typescript-eslint/utils": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.66.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-p088eaGrzYz1s+7cov0aMOCkNGTJlVxF4jgubf28c8L0Cv9Rloj8YBHnv4hXLq6IIEE1AsjNWavO+k+8kP2Y0A=="],
"web/typescript-eslint/@typescript-eslint/parser": ["@typescript-eslint/parser@8.66.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.66.0", "@typescript-eslint/types": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-X6ypGChaWYk6PBtUg2BwuTZEFFcHJAtGTVJ9/lCTOufhZ4i9fNolQNnktq+kkMCwMj7V8Svsq7+TxSDslmhE0g=="],
"web/typescript-eslint/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.66.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.66.0", "@typescript-eslint/tsconfig-utils": "8.66.0", "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-8/x4INiiQb10jGgXYD7116/zQ+OL84ZIFn0za68wwFHCanT/VLbBEroWht8RV8fn0/ZCAoazHLQgwUC0UQcDfg=="],
"web/typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.66.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.66.0", "@typescript-eslint/types": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-jasearZPolBw5NJNYGMwxzHMF83niVWmMU1VdHzG1CyfI2VS7f7nZltnKtHcg20hW+7Uo5GfK4MeDPoU3qI8EA=="],
"admin/eslint/@eslint/config-array/@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
"admin/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0" } }, "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g=="],
"admin/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0", "@typescript-eslint/utils": "8.66.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g=="],
"admin/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="],
"admin/typescript-eslint/@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"admin/typescript-eslint/@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0" } }, "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g=="],
"admin/typescript-eslint/@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"admin/typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="],
"admin/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.66.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.66.0", "@typescript-eslint/types": "^8.66.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g=="],
"admin/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.66.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g=="],
"admin/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"admin/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="],
"admin/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0" } }, "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g=="],
"admin/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"inter-app-api-showcase/eslint/@eslint/config-array/@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], "inter-app-api-showcase/eslint/@eslint/config-array/@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
"inter-app-api-showcase/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0" } }, "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g=="], "inter-app-api-showcase/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0" } }, "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g=="],
@@ -1394,6 +1577,42 @@
"inter-app-api-showcase/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="], "inter-app-api-showcase/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"web/eslint/@eslint/config-array/@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="],
"web/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0" } }, "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g=="],
"web/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/typescript-estree": "8.66.0", "@typescript-eslint/utils": "8.66.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-LG2dWfjZQQp0ADtAu/EWJVayefGL2UEZ3CDeI44D9v3rXB/WYUqE/jpO28KrEKul5AySrmI+Zh1v6v+xW2U9+g=="],
"web/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="],
"web/typescript-eslint/@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
"web/typescript-eslint/@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0" } }, "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g=="],
"web/typescript-eslint/@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"web/typescript-eslint/@typescript-eslint/parser/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="],
"web/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.66.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.66.0", "@typescript-eslint/types": "^8.66.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-7MthGPTt4BP69lSryqpqq8HQqxuzynssckL/jyDyk3+TNMQ3y2jFWkptCrktWvBrP+EH787Nl5N5Qpw7WZg+5g=="],
"web/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.66.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-9D5gLYZG4rOjcoag8MQ/fWI8WqA9wcPDyOGyWtWFhvM1lHRbliqUSPIY5J3zqCU1tvSwzXxnnjhQhz5Ne7mJ4g=="],
"web/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"web/typescript-eslint/@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="],
"web/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "@typescript-eslint/visitor-keys": "8.66.0" } }, "sha512-8TGcH25j9zqJ/IULB/ppyhRvxA8QYfFEZ7nfbg6/BN9spDgb8fPWQXlE5l8TWBL50EtUx007uZ1o9VOwrq2/9g=="],
"web/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"admin/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"admin/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"admin/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"admin/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="],
"inter-app-api-showcase/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="], "inter-app-api-showcase/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"inter-app-api-showcase/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="], "inter-app-api-showcase/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
@@ -1401,5 +1620,13 @@
"inter-app-api-showcase/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="], "inter-app-api-showcase/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"inter-app-api-showcase/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="], "inter-app-api-showcase/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="],
"web/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"web/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/type-utils/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"web/typescript-eslint/@typescript-eslint/eslint-plugin/@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.66.0", "", {}, "sha512-H6gcYaSDOyvL3AD/jHUtUFo2jqGgn/F6nuyuZSu0QTesxL+cP4dQoIMrODRofuJC09g64+WgZ6tE19Y1N2YIFQ=="],
"web/typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.66.0", "", { "dependencies": { "@typescript-eslint/types": "8.66.0", "eslint-visitor-keys": "^5.0.0" } }, "sha512-dkKR8q+lKciskj1Y3vthHktl+3cMLWGyVUP23bRiPZ5O9BRT++4EqDDV+TVeIKBL1VXVEqrJlz8MYbcnvJcAlg=="],
} }
} }
+12
View File
@@ -1,5 +1,17 @@
# Framework remediation plan # Framework remediation plan
**Status: completed 2026-08-09.** Every actionable item in this plan has been
implemented and covered by a failing-before regression or an enforceable
ratchet. The final repository state has 102 maintained UI components, zero
undeclared non-native output emitters, zero components matching the scaffold
definition, and local styles on every component. The core reactive runtime is
48,124 minified bytes; component controllers ship separately at 24,027 bytes.
Final validation passed the production, package, example, service, editor,
showcase-generation, typecheck, lint, formatting, public-API, visual-contract,
security, and runtime-size gates. The only skipped test is the explicitly
environment-dependent live PostgreSQL/MySQL test.
Written 2026-08-09, after the 0.8.6 release. Every number here was measured Written 2026-08-09, after the 0.8.6 release. Every number here was measured
against the tree at commit `7a2b5865`, not estimated. Where a cause is not yet against the tree at commit `7a2b5865`, not estimated. Where a cause is not yet
proven the item says so and makes proving it step one — nothing in this document proven the item says so and makes proving it step one — nothing in this document
+1 -1
View File
@@ -27,7 +27,7 @@
"packages/ui/components/ContextMenu.wrn": "33fb0f60268b12411d66e3031dc0557cb231149e7a8d83340b4b453a6e37cb09", "packages/ui/components/ContextMenu.wrn": "33fb0f60268b12411d66e3031dc0557cb231149e7a8d83340b4b453a6e37cb09",
"packages/ui/components/CustomScrollbar.wrn": "fedb2ab06cc2cf9499c130590945ca6971a3edfb60407b6658ef7756e4be9823", "packages/ui/components/CustomScrollbar.wrn": "fedb2ab06cc2cf9499c130590945ca6971a3edfb60407b6658ef7756e4be9823",
"packages/ui/components/DataMap.wrn": "7d0384d89126d947a6c2d640c93ab047aecca7931569d11b54d82dbb6639ff0e", "packages/ui/components/DataMap.wrn": "7d0384d89126d947a6c2d640c93ab047aecca7931569d11b54d82dbb6639ff0e",
"packages/ui/components/DataTable.wrn": "4e4562b0e18748f062a8b20153767aaaf62c33d98542ff14af4e57da7d8c2469", "packages/ui/components/DataTable.wrn": "68ad07f111e4fa5f2fc3547acc9558fa21720f8b27ac3b91494eb456dc796edc",
"packages/ui/components/DatePicker.wrn": "a9edc2faf30a0e998e964e9290ee6bd9512787aa5dc19f360bcce029796d7e1c", "packages/ui/components/DatePicker.wrn": "a9edc2faf30a0e998e964e9290ee6bd9512787aa5dc19f360bcce029796d7e1c",
"packages/ui/components/DeviceFrame.wrn": "1151090854901710971808f42dd2f1dcbd102e6afef63a5afecd01d4b3f0797d", "packages/ui/components/DeviceFrame.wrn": "1151090854901710971808f42dd2f1dcbd102e6afef63a5afecd01d4b3f0797d",
"packages/ui/components/Divider.wrn": "f5cc449611022b3d3eedf982ae48f6b1a289db7855cc9b6ea0248dcda807ffb3", "packages/ui/components/Divider.wrn": "f5cc449611022b3d3eedf982ae48f6b1a289db7855cc9b6ea0248dcda807ffb3",
+137 -61
View File
@@ -1,6 +1,6 @@
"use strict"; "use strict";
// Generated by scripts/build-editor-compiler.mjs. Do not edit directly. // Generated by scripts/build-editor-compiler.mjs. Do not edit directly.
// WRN editor compiler source hash: 451706f47a7734fd5808cdeeb5786e1b97a183afec98db99fc041369eb16a205 // WRN editor compiler source hash: 4f9249b868459eb792fcd6dc7814e440bd2c0ad6d08f1dec947939dc48db92b3
// WRN editor compiler generator hash: c71e7fe4258c97b73b384ff14b321f0cf0b30cc2ed0322f5f84b04e757159b18 // WRN editor compiler generator hash: c71e7fe4258c97b73b384ff14b321f0cf0b30cc2ed0322f5f84b04e757159b18
// Generated with TypeScript: 5.9.3 // Generated with TypeScript: 5.9.3
const __nodeRequire = require; const __nodeRequire = require;
@@ -558,7 +558,7 @@ function browserModuleRequired(ast) {
const functions = ast.runtimeFunctions.filter((fn) => ["legacy", "client", "shared"].includes(fn.runtime)); const functions = ast.runtimeFunctions.filter((fn) => ["legacy", "client", "shared"].includes(fn.runtime));
return functions.length > 0 || selectedBrowserImports(ast, functions).length > 0; return functions.length > 0 || selectedBrowserImports(ast, functions).length > 0;
} }
function functionEntry(ast, fn, availableFunctions) { function _functionEntry(ast, fn, availableFunctions) {
const parameterNames = new Set(fn.parameters.map((parameter) => parameter.name)); const parameterNames = new Set(fn.parameters.map((parameter) => parameter.name));
/* /*
* Names the function body declares for itself. * Names the function body declares for itself.
@@ -608,32 +608,42 @@ function functionEntry(ast, fn, availableFunctions) {
const syncStateFromContext = stateNames const syncStateFromContext = stateNames
.map((name) => `${name} = context.state.${name};`) .map((name) => `${name} = context.state.${name};`)
.join(" "); .join(" ");
const peerAliases = functionAliases const peerAliases = !stateNames.length
.map((name) => { ? functionAliases
const call = `context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs)`; .map((name) => `const ${name} = (...__wrnexusPeerArgs) => context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs);`)
if (!stateNames.length) { .join("\n")
return `const ${name} = (...__wrnexusPeerArgs) => ${call};`; : `const __wrnexusFlush = () => { ${syncStateToContext} };
} const __wrnexusRestore = () => { ${syncStateFromContext} };
return `const ${name} = (...__wrnexusPeerArgs) => { const __wrnexusPeer = (name, args) => {
${syncStateToContext} __wrnexusFlush();
let __wrnexusPeerResult; let result;
try { try {
__wrnexusPeerResult = ${call}; result = context.functions[name](...args);
} catch (__wrnexusPeerError) { } catch (error) {
${syncStateFromContext} __wrnexusRestore();
throw __wrnexusPeerError; throw error;
} }
if (__wrnexusPeerResult && typeof __wrnexusPeerResult.then === "function") { if (result && typeof result.then === "function") {
return Promise.resolve(__wrnexusPeerResult).finally(() => { ${syncStateFromContext} }); return Promise.resolve(result).finally(__wrnexusRestore);
} }
${syncStateFromContext} __wrnexusRestore();
return __wrnexusPeerResult; return result;
};`; };
}) ${functionAliases.map((name) => `const ${name} = (...__wrnexusPeerArgs) => __wrnexusPeer(${JSON.stringify(name)}, __wrnexusPeerArgs);`).join("\n")}`;
.join("\n");
const copyBack = stateNames const copyBack = stateNames
.map((name) => `if (!Object.is(${name}, __wrnexusInitialState[${JSON.stringify(name)}])) context.state.${name} = ${name};`) .map((name) => `if (!Object.is(${name}, __wrnexusInitialState[${JSON.stringify(name)}])) context.state.${name} = ${name};`)
.join("\n"); .join("\n");
const commitBinding = stateNames.length
? `const __wrnexusCommit = () => { ${copyBack} };
${!parameterNames.has("commit") && !declaredLocals.has("commit") && !functionAliases.includes("commit") ? "const commit = __wrnexusCommit;" : ""}
${!parameterNames.has("setTimeout") &&
!declaredLocals.has("setTimeout") &&
!functionAliases.includes("setTimeout")
? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);`
: ""}`
: "";
const body = (0, syntax_1.eraseFunctionTypes)(fn.body); const body = (0, syntax_1.eraseFunctionTypes)(fn.body);
const runtimeBindings = [ const runtimeBindings = [
!parameterNames.has("output") ? "const output = context.output;" : "", !parameterNames.has("output") ? "const output = context.output;" : "",
@@ -647,12 +657,13 @@ function functionEntry(ast, fn, availableFunctions) {
${initialStateSnapshot} ${initialStateSnapshot}
${stateAliases} ${stateAliases}
${propAliases} ${propAliases}
${commitBinding}
${peerAliases} ${peerAliases}
${runtimeBindings} ${runtimeBindings}
try { try {
${body} ${body}
} finally { } finally {
${copyBack} ${stateNames.length ? "__wrnexusCommit();" : ""}
} }
}`; }`;
} }
@@ -663,22 +674,74 @@ function generateBrowserModule(ast) {
const selectedImports = selectedBrowserImports(ast, functions); const selectedImports = selectedBrowserImports(ast, functions);
const imports = selectedImports.map((entry) => entry.code).join("\n"); const imports = selectedImports.map((entry) => entry.code).join("\n");
const importedBindings = [...new Set(selectedImports.flatMap((entry) => entry.bindings))]; const importedBindings = [...new Set(selectedImports.flatMap((entry) => entry.bindings))];
const sharedState = state.filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name));
const sharedProps = ast.props
.map((entry) => entry.name)
.filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name) && !sharedState.includes(name));
const callableAliases = functionNames.filter((name) => safeIdentifier(name) &&
!RUNTIME_BINDINGS.has(name) &&
!sharedState.includes(name) &&
!sharedProps.includes(name));
const sharedCommit = sharedState.map((name) => `context.state.${name} = ${name};`).join(" ");
const sharedRestore = [
...sharedState.map((name) => `${name} = context.state.${name};`),
...sharedProps.map((name) => `${name} = context.props.${name};`),
].join(" ");
const hasAuthoredCommit = callableAliases.includes("commit");
const hasAuthoredSetTimeout = callableAliases.includes("setTimeout");
const implementations = functions
.map((fn) => {
const parameters = fn.parameters.map((parameter) => parameter.name).join(", ");
return `${JSON.stringify(fn.name)}: ${fn.async ? "async " : ""}function(${parameters}) {
try { ${(0, syntax_1.eraseFunctionTypes)(fn.body)} } finally { __wrnexusCommit(); }
}`;
})
.join(",\n");
return `// generated WRNexusJS browser module for ${ast.name} return `// generated WRNexusJS browser module for ${ast.name}
${imports} ${imports}
export const __wrnexusClientFunctions = { export const __wrnexusClientFunctions = {
${functions.map((fn) => ` ${functionEntry(ast, fn, functionNames)}`).join(",\n")} ${functions
.map((fn) => ` ${JSON.stringify(fn.name)}: (context, ...args) => __wrnexusBindings(context)[${JSON.stringify(fn.name)}](...args)`)
.join(",\n")}
}; };
export const __wrnexusClientState = ${JSON.stringify(state)}; export const __wrnexusClientState = ${JSON.stringify(state)};
export const __wrnexusOutputs = ${JSON.stringify(ast.outputs)}; export const __wrnexusOutputs = ${JSON.stringify(ast.outputs)};
export const __wrnexusImportedBindings = { ${importedBindings.join(", ")} }; export const __wrnexusImportedBindings = { ${importedBindings.join(", ")} };
export function bindClientScope(context) { function __wrnexusCreateClientFunctions(context) {
${sharedState.length ? `let { ${sharedState.join(", ")} } = context.state;` : ""}
${sharedProps.length ? `let { ${sharedProps.join(", ")} } = context.props;` : ""}
const output = context.output;
const server = context.server;
const props = context.props;
const refs = context.refs;
const __wrnexusCommit = () => { ${sharedCommit} };
const __wrnexusRestore = () => { ${sharedRestore} };
${!hasAuthoredCommit ? "const commit = __wrnexusCommit;" : ""}
${!hasAuthoredSetTimeout
? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);`
: ""}
const implementations = {
${implementations}
};
${callableAliases.map((name) => `const ${name} = (...args) => implementations[${JSON.stringify(name)}](...args);`).join("\n ")}
const functions = {}; const functions = {};
const scopedContext = { ...context, functions }; for (const name of Object.keys(implementations)) {
for (const [name, handler] of Object.entries(__wrnexusClientFunctions)) { functions[name] = (...args) => {
functions[name] = (...args) => handler(scopedContext, ...args); __wrnexusRestore();
return implementations[name](...args);
};
} }
return functions; return functions;
} }
function __wrnexusBindings(context) {
return context.__wrnexusBoundFunctions ||
(context.__wrnexusBoundFunctions = __wrnexusCreateClientFunctions(context));
}
export function bindClientScope(context) {
return __wrnexusBindings(context);
}
`; `;
} }
@@ -1282,13 +1345,12 @@ function renderNestedComponentInvocation(node, ctx) {
? `\${__wireProp(${ctx.resolveExpr(wholeExpression)})}` ? `\${__wireProp(${ctx.resolveExpr(wholeExpression)})}`
: compileAttrValue(attr.value, ctx); : compileAttrValue(attr.value, ctx);
const rendered = ` ${attr.name}="${compiledValue}"`; const rendered = ` ${attr.name}="${compiledValue}"`;
if (wholeExpression || if (!attr.value.includes("{") ||
!attr.value.includes("{") || (!exprRefsState(attr.value, ctx.stateNames) && !exprRefsState(attr.value, ctx.propNames))) {
!exprRefsState(attr.value, ctx.stateNames)) {
return rendered; return rendered;
} }
const marker = attrEscape(JSON.stringify([attr.name, attr.value])); const marker = attrEscape(JSON.stringify([attr.name, attr.value]));
return rendered + ` data-wrn-bind-${bindIndex++}="${escLit(marker)}"`; return rendered + ` data-wrn-prop-bind-${bindIndex++}="${escLit(marker)}"`;
}) })
.join(""); .join("");
const loops = loopVarsOf(node); const loops = loopVarsOf(node);
@@ -2178,7 +2240,9 @@ function exprRefsState(expr, stateNames) {
return false; return false;
} }
function exprRefsComponentReactiveValue(expr, ctx) { function exprRefsComponentReactiveValue(expr, ctx) {
return exprRefsState(expr, ctx.stateNames) || exprRefsState(expr, ctx.functionNames); return (exprRefsState(expr, ctx.stateNames) ||
exprRefsState(expr, ctx.propNames) ||
exprRefsState(expr, ctx.functionNames));
} }
function viewHasEvents(nodes) { function viewHasEvents(nodes) {
return nodes.some((node) => { return nodes.some((node) => {
@@ -2242,6 +2306,9 @@ function compileText(raw, ctx) {
// list renderer fills it per item; it has no server-side value. // list renderer fills it per item; it has no server-side value.
out += escLit(`{${expr}}`); out += escLit(`{${expr}}`);
} }
else if (expr === "content") {
out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`;
}
else if (exprRefsComponentReactiveValue(expr, ctx)) { else if (exprRefsComponentReactiveValue(expr, ctx)) {
// State interpolation: bake the initial value AND keep it reactive via a // State interpolation: bake the initial value AND keep it reactive via a
// data-text span, so no-JS clients see the real value and hydration // data-text span, so no-JS clients see the real value and hydration
@@ -2251,9 +2318,6 @@ function compileText(raw, ctx) {
`\${__wireHtml(${ctx.resolveExpr(expr)})}` + `\${__wireHtml(${ctx.resolveExpr(expr)})}` +
escLit(`</span>`); escLit(`</span>`);
} }
else if (expr === "content") {
out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`;
}
else { else {
out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`; out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`;
} }
@@ -2593,6 +2657,7 @@ function generateComponent(ast) {
}; };
const ctx = { const ctx = {
stateNames, stateNames,
propNames: new Set(effectiveProps.map((entry) => entry.name)),
functionNames: new Set(ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name)), functionNames: new Set(ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name)),
resolveExpr, resolveExpr,
eventNames: publicOutputNames(ast), eventNames: publicOutputNames(ast),
@@ -2610,12 +2675,12 @@ function generateComponent(ast) {
.join(""); .join("");
const styles = ast.styles.map((body) => body.trim()).filter(Boolean); const styles = ast.styles.map((body) => body.trim()).filter(Boolean);
const styleTag = escLit(localStyleTag(ast, styles)); const styleTag = escLit(localStyleTag(ast, styles));
// A component needs a reactive scope only when it has state or event handlers. // Props remain server-rendered and also become signals so a parent can drive
// Prop-driven text/attributes are baked server-side, so static components ship // a mounted child after hydration.
// no JavaScript at all.
const behavior = componentBehavior(ast); const behavior = componentBehavior(ast);
const needsScope = ast.runtime !== "server" && const needsScope = ast.runtime !== "server" &&
(browserStates.length > 0 || (effectiveProps.length > 0 ||
browserStates.length > 0 ||
ast.computed.length > 0 || ast.computed.length > 0 ||
viewHasEvents(ast.view) || viewHasEvents(ast.view) ||
behavior !== null); behavior !== null);
@@ -2632,7 +2697,7 @@ function generateComponent(ast) {
if (prop.required) { if (prop.required) {
decls.push(` if (__p[${JSON.stringify(prop.name)}] === undefined) throw new TypeError(${JSON.stringify(`${ast.name} requires prop '${prop.name}' (${prop.valueType ?? "unknown"})`)});`); decls.push(` if (__p[${JSON.stringify(prop.name)}] === undefined) throw new TypeError(${JSON.stringify(`${ast.name} requires prop '${prop.name}' (${prop.valueType ?? "unknown"})`)});`);
} }
decls.push(` const ${nameRefs.get(prop.name)}: ${prop.valueType ?? "any"} = __coerce(__p[${JSON.stringify(prop.name)}], (${resolveExpr(prop.default)}), ${JSON.stringify((0, types_ts_1.runtimeTypeOf)(prop.valueType))});`); decls.push(` const ${nameRefs.get(prop.name)}: ${prop.valueType ?? "any"} = __coerce(__p[${JSON.stringify(prop.name)}], (${resolveExpr(prop.default)}), ${JSON.stringify((0, types_ts_1.runtimeTypeOf)(prop.valueType))}, ${JSON.stringify(prop.name)});`);
} }
if (!effectiveProps.some((prop) => prop.name === "attrs")) { if (!effectiveProps.some((prop) => prop.name === "attrs")) {
decls.push(` const __attrs = __restProps(__p, new Set(${JSON.stringify(effectiveProps.map((prop) => prop.name))}));`); decls.push(` const __attrs = __restProps(__p, new Set(${JSON.stringify(effectiveProps.map((prop) => prop.name))}));`);
@@ -2697,7 +2762,7 @@ function generateComponent(ast) {
.map((output) => ` ${JSON.stringify(output.name)}(${output.payload ? `${output.payload.name}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}): void;`) .map((output) => ` ${JSON.stringify(output.name)}(${output.payload ? `${output.payload.name}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}): void;`)
.join("\n")}\n}`); .join("\n")}\n}`);
} }
out.push(`function __coerce(v: any, def: any, declared: string = "unknown"): any { out.push(`function __coerce(v: any, def: any, declared: string = "unknown", propName: string = "prop"): any {
if (v === undefined || v === null) { if (v === undefined || v === null) {
return def; return def;
} }
@@ -2722,14 +2787,14 @@ function generateComponent(ast) {
if (typeof v === "string") { if (typeof v === "string") {
try { try {
const parsed = JSON.parse(v); const parsed = JSON.parse(v);
return Array.isArray(parsed) ? parsed : def; if (!Array.isArray(parsed)) throw new TypeError("Expected an array prop '" + propName + "'");
return parsed;
} catch { } catch {
if (declared === "array") throw new TypeError("Expected an array prop"); throw new TypeError("Expected an array prop '" + propName + "'");
return def;
} }
} }
return def; throw new TypeError("Expected an array prop '" + propName + "'");
} }
if (declared === "object" || (def !== null && typeof def === "object")) { if (declared === "object" || (def !== null && typeof def === "object")) {
@@ -2745,20 +2810,16 @@ function generateComponent(ast) {
try { try {
const parsed = JSON.parse(v); const parsed = JSON.parse(v);
return ( if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
parsed !== null && throw new TypeError("Expected an object prop '" + propName + "'");
typeof parsed === "object" && }
!Array.isArray(parsed) return parsed;
)
? parsed
: def;
} catch { } catch {
if (declared === "object") throw new TypeError("Expected an object prop"); throw new TypeError("Expected an object prop '" + propName + "'");
return def;
} }
} }
return def; throw new TypeError("Expected an object prop '" + propName + "'");
} }
if (declared === "bigint") return BigInt(v); if (declared === "bigint") return BigInt(v);
@@ -2828,10 +2889,12 @@ function __wireSpreadAttrs(value: any): string {
lowerName === "style" || lowerName === "style" ||
lowerName === "slot" || lowerName === "slot" ||
lowerName === "data-component" || lowerName === "data-component" ||
// Internal markers must not leak through a spread -- except the // Internal markers must not leak through a spread. Parent-owned output
// parent's output handlers, whose whole job is to ride from the mount // and prop bindings ride from the mount onto the
// onto the view root so the mounting scope can bind them there. // rendered child root so the mounting scope can bind them there.
(lowerName.startsWith("data-wrn") && !lowerName.startsWith("data-wrn-out-")) (lowerName.startsWith("data-wrn") &&
!lowerName.startsWith("data-wrn-out-") &&
!lowerName.startsWith("data-wrn-prop-bind-"))
) { ) {
continue; continue;
} }
@@ -5634,7 +5697,12 @@ function parse(source) {
// props { name: Type = <default>; @event name = function } // props { name: Type = <default>; @event name = function }
lx.next(); lx.next();
expect("lbrace"); expect("lbrace");
while (lx.peek().type !== "rbrace") { while (true) {
if (lx.startsWithBlockComment()) {
throw new ParseError("Block comments are not allowed inside props {}; use // line comments instead", "WRN-PROPS-BLOCK-COMMENT");
}
if (lx.peek().type === "rbrace")
break;
const t = lx.peek(); const t = lx.peek();
if (t.type === "eof") if (t.type === "eof")
throw new ParseError("Unexpected end of input inside props"); throw new ParseError("Unexpected end of input inside props");
@@ -6013,6 +6081,9 @@ function parse(source) {
} }
expect("rbrace"); expect("rbrace");
const declaredStates = new Set(states.map((state) => state.name)); const declaredStates = new Set(states.map((state) => state.name));
if (declaredStates.has("page")) {
throw new ParseError("State name 'page' collides with the WRN 'page' keyword; choose another state name", "WRN-STATE-RESERVED-NAME");
}
for (const watcher of watches) { for (const watcher of watches) {
if (!declaredStates.has(watcher.state)) { if (!declaredStates.has(watcher.state)) {
throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`); throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`);
@@ -6543,6 +6614,11 @@ class Lexer {
break; break;
} }
} }
/** True when the next non-trivia characters open a block comment. */
startsWithBlockComment() {
this.skipTrivia();
return this.src[this.pos] === "/" && this.src[this.pos + 1] === "*";
}
/** Read and consume the next structural token. */ /** Read and consume the next structural token. */
next() { next() {
this.skipTrivia(); this.skipTrivia();
+112 -54
View File
@@ -1,4 +1,4 @@
// WRN editor extension source hash: 6165420f37af57e441086efeb6b25528f72e77a39abb2c76ca5bc8748dd90c2f // WRN editor extension source hash: c09cc127dcc7fbae562648b09435fb96134c18e63ba21d7a4b476b916f4a8256
// WRN editor extension generator hash: 456d1d614e44e5fb1f19b784176c09cf2ade9b64ef73a17934c2698150b62728 // WRN editor extension generator hash: 456d1d614e44e5fb1f19b784176c09cf2ade9b64ef73a17934c2698150b62728
"use strict"; "use strict";
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports); var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
@@ -23202,7 +23202,7 @@ ${(0, codegen_ts_1.generate)(ast)}`,
const functions = ast.runtimeFunctions.filter((fn) => ["legacy", "client", "shared"].includes(fn.runtime)); const functions = ast.runtimeFunctions.filter((fn) => ["legacy", "client", "shared"].includes(fn.runtime));
return functions.length > 0 || selectedBrowserImports(ast, functions).length > 0; return functions.length > 0 || selectedBrowserImports(ast, functions).length > 0;
} }
function functionEntry(ast, fn, availableFunctions) { function _functionEntry(ast, fn, availableFunctions) {
const parameterNames = new Set(fn.parameters.map((parameter) => parameter.name)); const parameterNames = new Set(fn.parameters.map((parameter) => parameter.name));
const declaredLocals = new Set; const declaredLocals = new Set;
for (const match of fn.body.matchAll(/\b(?:var|let|const)\s+([A-Za-z_$][\w$]*)|\bfunction\s+([A-Za-z_$][\w$]*)/g)) { for (const match of fn.body.matchAll(/\b(?:var|let|const)\s+([A-Za-z_$][\w$]*)|\bfunction\s+([A-Za-z_$][\w$]*)/g)) {
@@ -23220,30 +23220,33 @@ ${(0, codegen_ts_1.generate)(ast)}`,
const propAliases = propNames.length ? `const { ${propNames.join(", ")} } = context.props;` : ""; const propAliases = propNames.length ? `const { ${propNames.join(", ")} } = context.props;` : "";
const syncStateToContext = stateNames.map((name) => `context.state.${name} = ${name};`).join(" "); const syncStateToContext = stateNames.map((name) => `context.state.${name} = ${name};`).join(" ");
const syncStateFromContext = stateNames.map((name) => `${name} = context.state.${name};`).join(" "); const syncStateFromContext = stateNames.map((name) => `${name} = context.state.${name};`).join(" ");
const peerAliases = functionAliases.map((name) => { const peerAliases = !stateNames.length ? functionAliases.map((name) => `const ${name} = (...__wrnexusPeerArgs) => context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs);`).join(`
const call = `context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs)`; `) : `const __wrnexusFlush = () => { ${syncStateToContext} };
if (!stateNames.length) { const __wrnexusRestore = () => { ${syncStateFromContext} };
return `const ${name} = (...__wrnexusPeerArgs) => ${call};`; const __wrnexusPeer = (name, args) => {
} __wrnexusFlush();
return `const ${name} = (...__wrnexusPeerArgs) => { let result;
${syncStateToContext}
let __wrnexusPeerResult;
try { try {
__wrnexusPeerResult = ${call}; result = context.functions[name](...args);
} catch (__wrnexusPeerError) { } catch (error) {
${syncStateFromContext} __wrnexusRestore();
throw __wrnexusPeerError; throw error;
} }
if (__wrnexusPeerResult && typeof __wrnexusPeerResult.then === "function") { if (result && typeof result.then === "function") {
return Promise.resolve(__wrnexusPeerResult).finally(() => { ${syncStateFromContext} }); return Promise.resolve(result).finally(__wrnexusRestore);
} }
${syncStateFromContext} __wrnexusRestore();
return __wrnexusPeerResult; return result;
};`; };
}).join(` ${functionAliases.map((name) => `const ${name} = (...__wrnexusPeerArgs) => __wrnexusPeer(${JSON.stringify(name)}, __wrnexusPeerArgs);`).join(`
`); `)}`;
const copyBack = stateNames.map((name) => `if (!Object.is(${name}, __wrnexusInitialState[${JSON.stringify(name)}])) context.state.${name} = ${name};`).join(` const copyBack = stateNames.map((name) => `if (!Object.is(${name}, __wrnexusInitialState[${JSON.stringify(name)}])) context.state.${name} = ${name};`).join(`
`); `);
const commitBinding = stateNames.length ? `const __wrnexusCommit = () => { ${copyBack} };
${!parameterNames.has("commit") && !declaredLocals.has("commit") && !functionAliases.includes("commit") ? "const commit = __wrnexusCommit;" : ""}
${!parameterNames.has("setTimeout") && !declaredLocals.has("setTimeout") && !functionAliases.includes("setTimeout") ? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);` : ""}` : "";
const body = (0, syntax_1.eraseFunctionTypes)(fn.body); const body = (0, syntax_1.eraseFunctionTypes)(fn.body);
const runtimeBindings = [ const runtimeBindings = [
!parameterNames.has("output") ? "const output = context.output;" : "", !parameterNames.has("output") ? "const output = context.output;" : "",
@@ -23256,12 +23259,13 @@ ${(0, codegen_ts_1.generate)(ast)}`,
${initialStateSnapshot} ${initialStateSnapshot}
${stateAliases} ${stateAliases}
${propAliases} ${propAliases}
${commitBinding}
${peerAliases} ${peerAliases}
${runtimeBindings} ${runtimeBindings}
try { try {
${body} ${body}
} finally { } finally {
${copyBack} ${stateNames.length ? "__wrnexusCommit();" : ""}
} }
}`; }`;
} }
@@ -23273,23 +23277,66 @@ ${(0, codegen_ts_1.generate)(ast)}`,
const imports = selectedImports.map((entry) => entry.code).join(` const imports = selectedImports.map((entry) => entry.code).join(`
`); `);
const importedBindings = [...new Set(selectedImports.flatMap((entry) => entry.bindings))]; const importedBindings = [...new Set(selectedImports.flatMap((entry) => entry.bindings))];
const sharedState = state.filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name));
const sharedProps = ast.props.map((entry) => entry.name).filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name) && !sharedState.includes(name));
const callableAliases = functionNames.filter((name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name) && !sharedState.includes(name) && !sharedProps.includes(name));
const sharedCommit = sharedState.map((name) => `context.state.${name} = ${name};`).join(" ");
const sharedRestore = [
...sharedState.map((name) => `${name} = context.state.${name};`),
...sharedProps.map((name) => `${name} = context.props.${name};`)
].join(" ");
const hasAuthoredCommit = callableAliases.includes("commit");
const hasAuthoredSetTimeout = callableAliases.includes("setTimeout");
const implementations = functions.map((fn) => {
const parameters = fn.parameters.map((parameter) => parameter.name).join(", ");
return `${JSON.stringify(fn.name)}: ${fn.async ? "async " : ""}function(${parameters}) {
try { ${(0, syntax_1.eraseFunctionTypes)(fn.body)} } finally { __wrnexusCommit(); }
}`;
}).join(`,
`);
return `// generated WRNexusJS browser module for ${ast.name} return `// generated WRNexusJS browser module for ${ast.name}
${imports} ${imports}
export const __wrnexusClientFunctions = { export const __wrnexusClientFunctions = {
${functions.map((fn) => ` ${functionEntry(ast, fn, functionNames)}`).join(`, ${functions.map((fn) => ` ${JSON.stringify(fn.name)}: (context, ...args) => __wrnexusBindings(context)[${JSON.stringify(fn.name)}](...args)`).join(`,
`)} `)}
}; };
export const __wrnexusClientState = ${JSON.stringify(state)}; export const __wrnexusClientState = ${JSON.stringify(state)};
export const __wrnexusOutputs = ${JSON.stringify(ast.outputs)}; export const __wrnexusOutputs = ${JSON.stringify(ast.outputs)};
export const __wrnexusImportedBindings = { ${importedBindings.join(", ")} }; export const __wrnexusImportedBindings = { ${importedBindings.join(", ")} };
export function bindClientScope(context) { function __wrnexusCreateClientFunctions(context) {
${sharedState.length ? `let { ${sharedState.join(", ")} } = context.state;` : ""}
${sharedProps.length ? `let { ${sharedProps.join(", ")} } = context.props;` : ""}
const output = context.output;
const server = context.server;
const props = context.props;
const refs = context.refs;
const __wrnexusCommit = () => { ${sharedCommit} };
const __wrnexusRestore = () => { ${sharedRestore} };
${!hasAuthoredCommit ? "const commit = __wrnexusCommit;" : ""}
${!hasAuthoredSetTimeout ? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);` : ""}
const implementations = {
${implementations}
};
${callableAliases.map((name) => `const ${name} = (...args) => implementations[${JSON.stringify(name)}](...args);`).join(`
`)}
const functions = {}; const functions = {};
const scopedContext = { ...context, functions }; for (const name of Object.keys(implementations)) {
for (const [name, handler] of Object.entries(__wrnexusClientFunctions)) { functions[name] = (...args) => {
functions[name] = (...args) => handler(scopedContext, ...args); __wrnexusRestore();
return implementations[name](...args);
};
} }
return functions; return functions;
} }
function __wrnexusBindings(context) {
return context.__wrnexusBoundFunctions ||
(context.__wrnexusBoundFunctions = __wrnexusCreateClientFunctions(context));
}
export function bindClientScope(context) {
return __wrnexusBindings(context);
}
`; `;
} }
}, },
@@ -23719,11 +23766,11 @@ export function bindClientScope(context) {
const wholeExpression = wholeAttributeExpression(attr.value); const wholeExpression = wholeAttributeExpression(attr.value);
const compiledValue = wholeExpression ? `\${__wireProp(${ctx.resolveExpr(wholeExpression)})}` : compileAttrValue(attr.value, ctx); const compiledValue = wholeExpression ? `\${__wireProp(${ctx.resolveExpr(wholeExpression)})}` : compileAttrValue(attr.value, ctx);
const rendered = ` ${attr.name}="${compiledValue}"`; const rendered = ` ${attr.name}="${compiledValue}"`;
if (wholeExpression || !attr.value.includes("{") || !exprRefsState(attr.value, ctx.stateNames)) { if (!attr.value.includes("{") || !exprRefsState(attr.value, ctx.stateNames) && !exprRefsState(attr.value, ctx.propNames)) {
return rendered; return rendered;
} }
const marker = attrEscape(JSON.stringify([attr.name, attr.value])); const marker = attrEscape(JSON.stringify([attr.name, attr.value]));
return rendered + ` data-wrn-bind-${bindIndex++}="${escLit(marker)}"`; return rendered + ` data-wrn-prop-bind-${bindIndex++}="${escLit(marker)}"`;
}).join(""); }).join("");
const loops = loopVarsOf(node); const loops = loopVarsOf(node);
const childCtx = loops.length > 0 ? { const childCtx = loops.length > 0 ? {
@@ -24547,7 +24594,7 @@ ${handlers.join(`
return false; return false;
} }
function exprRefsComponentReactiveValue(expr, ctx) { function exprRefsComponentReactiveValue(expr, ctx) {
return exprRefsState(expr, ctx.stateNames) || exprRefsState(expr, ctx.functionNames); return exprRefsState(expr, ctx.stateNames) || exprRefsState(expr, ctx.propNames) || exprRefsState(expr, ctx.functionNames);
} }
function viewHasEvents(nodes) { function viewHasEvents(nodes) {
return nodes.some((node) => { return nodes.some((node) => {
@@ -24599,10 +24646,10 @@ ${handlers.join(`
out += escLit(`<span data-t="${attrEscape(expr.slice(2).trim())}"></span>`); out += escLit(`<span data-t="${attrEscape(expr.slice(2).trim())}"></span>`);
} else if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) { } else if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) {
out += escLit(`{${expr}}`); out += escLit(`{${expr}}`);
} else if (exprRefsComponentReactiveValue(expr, ctx)) {
out += escLit(`<span data-text="${attrEscape(expr)}">`) + `\${__wireHtml(${ctx.resolveExpr(expr)})}` + escLit(`</span>`);
} else if (expr === "content") { } else if (expr === "content") {
out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`; out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`;
} else if (exprRefsComponentReactiveValue(expr, ctx)) {
out += escLit(`<span data-text="${attrEscape(expr)}">`) + `\${__wireHtml(${ctx.resolveExpr(expr)})}` + escLit(`</span>`);
} else { } else {
out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`; out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`;
} }
@@ -24855,6 +24902,7 @@ ${handlers.join(`
}; };
const ctx = { const ctx = {
stateNames, stateNames,
propNames: new Set(effectiveProps.map((entry) => entry.name)),
functionNames: new Set(ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name)), functionNames: new Set(ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name)),
resolveExpr, resolveExpr,
eventNames: publicOutputNames(ast) eventNames: publicOutputNames(ast)
@@ -24867,7 +24915,7 @@ ${handlers.join(`
const styles = ast.styles.map((body) => body.trim()).filter(Boolean); const styles = ast.styles.map((body) => body.trim()).filter(Boolean);
const styleTag = escLit(localStyleTag(ast, styles)); const styleTag = escLit(localStyleTag(ast, styles));
const behavior = componentBehavior(ast); const behavior = componentBehavior(ast);
const needsScope = ast.runtime !== "server" && (browserStates.length > 0 || ast.computed.length > 0 || viewHasEvents(ast.view) || behavior !== null); const needsScope = ast.runtime !== "server" && (effectiveProps.length > 0 || browserStates.length > 0 || ast.computed.length > 0 || viewHasEvents(ast.view) || behavior !== null);
if (hasServerEach || needsScope) { if (hasServerEach || needsScope) {
out.push(`import { Buffer as __WrnexusBuffer } from "node:buffer";`); out.push(`import { Buffer as __WrnexusBuffer } from "node:buffer";`);
} }
@@ -24881,7 +24929,7 @@ ${handlers.join(`
if (prop.required) { if (prop.required) {
decls.push(` if (__p[${JSON.stringify(prop.name)}] === undefined) throw new TypeError(${JSON.stringify(`${ast.name} requires prop '${prop.name}' (${prop.valueType ?? "unknown"})`)});`); decls.push(` if (__p[${JSON.stringify(prop.name)}] === undefined) throw new TypeError(${JSON.stringify(`${ast.name} requires prop '${prop.name}' (${prop.valueType ?? "unknown"})`)});`);
} }
decls.push(` const ${nameRefs.get(prop.name)}: ${prop.valueType ?? "any"} = __coerce(__p[${JSON.stringify(prop.name)}], (${resolveExpr(prop.default)}), ${JSON.stringify((0, types_ts_1.runtimeTypeOf)(prop.valueType))});`); decls.push(` const ${nameRefs.get(prop.name)}: ${prop.valueType ?? "any"} = __coerce(__p[${JSON.stringify(prop.name)}], (${resolveExpr(prop.default)}), ${JSON.stringify((0, types_ts_1.runtimeTypeOf)(prop.valueType))}, ${JSON.stringify(prop.name)});`);
} }
if (!effectiveProps.some((prop) => prop.name === "attrs")) { if (!effectiveProps.some((prop) => prop.name === "attrs")) {
decls.push(` const __attrs = __restProps(__p, new Set(${JSON.stringify(effectiveProps.map((prop) => prop.name))}));`); decls.push(` const __attrs = __restProps(__p, new Set(${JSON.stringify(effectiveProps.map((prop) => prop.name))}));`);
@@ -24941,7 +24989,7 @@ ${ast.outputs.map((output) => ` ${JSON.stringify(output.name)}(${output.payload
`)} `)}
}`); }`);
} }
out.push(`function __coerce(v: any, def: any, declared: string = "unknown"): any { out.push(`function __coerce(v: any, def: any, declared: string = "unknown", propName: string = "prop"): any {
if (v === undefined || v === null) { if (v === undefined || v === null) {
return def; return def;
} }
@@ -24966,14 +25014,14 @@ ${ast.outputs.map((output) => ` ${JSON.stringify(output.name)}(${output.payload
if (typeof v === "string") { if (typeof v === "string") {
try { try {
const parsed = JSON.parse(v); const parsed = JSON.parse(v);
return Array.isArray(parsed) ? parsed : def; if (!Array.isArray(parsed)) throw new TypeError("Expected an array prop '" + propName + "'");
return parsed;
} catch { } catch {
if (declared === "array") throw new TypeError("Expected an array prop"); throw new TypeError("Expected an array prop '" + propName + "'");
return def;
} }
} }
return def; throw new TypeError("Expected an array prop '" + propName + "'");
} }
if (declared === "object" || (def !== null && typeof def === "object")) { if (declared === "object" || (def !== null && typeof def === "object")) {
@@ -24989,20 +25037,16 @@ ${ast.outputs.map((output) => ` ${JSON.stringify(output.name)}(${output.payload
try { try {
const parsed = JSON.parse(v); const parsed = JSON.parse(v);
return ( if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
parsed !== null && throw new TypeError("Expected an object prop '" + propName + "'");
typeof parsed === "object" && }
!Array.isArray(parsed) return parsed;
)
? parsed
: def;
} catch { } catch {
if (declared === "object") throw new TypeError("Expected an object prop"); throw new TypeError("Expected an object prop '" + propName + "'");
return def;
} }
} }
return def; throw new TypeError("Expected an object prop '" + propName + "'");
} }
if (declared === "bigint") return BigInt(v); if (declared === "bigint") return BigInt(v);
@@ -25072,10 +25116,12 @@ function __wireSpreadAttrs(value: any): string {
lowerName === "style" || lowerName === "style" ||
lowerName === "slot" || lowerName === "slot" ||
lowerName === "data-component" || lowerName === "data-component" ||
// Internal markers must not leak through a spread -- except the // Internal markers must not leak through a spread. Parent-owned output
// parent's output handlers, whose whole job is to ride from the mount // and prop bindings ride from the mount onto the
// onto the view root so the mounting scope can bind them there. // rendered child root so the mounting scope can bind them there.
(lowerName.startsWith("data-wrn") && !lowerName.startsWith("data-wrn-out-")) (lowerName.startsWith("data-wrn") &&
!lowerName.startsWith("data-wrn-out-") &&
!lowerName.startsWith("data-wrn-prop-bind-"))
) { ) {
continue; continue;
} }
@@ -27916,7 +27962,12 @@ ${serverFunctions}
case "props": { case "props": {
lx.next(); lx.next();
expect("lbrace"); expect("lbrace");
while (lx.peek().type !== "rbrace") { while (true) {
if (lx.startsWithBlockComment()) {
throw new ParseError("Block comments are not allowed inside props {}; use // line comments instead", "WRN-PROPS-BLOCK-COMMENT");
}
if (lx.peek().type === "rbrace")
break;
const t = lx.peek(); const t = lx.peek();
if (t.type === "eof") if (t.type === "eof")
throw new ParseError("Unexpected end of input inside props"); throw new ParseError("Unexpected end of input inside props");
@@ -28275,6 +28326,9 @@ ${serverFunctions}
} }
expect("rbrace"); expect("rbrace");
const declaredStates = new Set(states.map((state) => state.name)); const declaredStates = new Set(states.map((state) => state.name));
if (declaredStates.has("page")) {
throw new ParseError("State name 'page' collides with the WRN 'page' keyword; choose another state name", "WRN-STATE-RESERVED-NAME");
}
for (const watcher of watches) { for (const watcher of watches) {
if (!declaredStates.has(watcher.state)) { if (!declaredStates.has(watcher.state)) {
throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`); throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`);
@@ -28748,6 +28802,10 @@ ${serverFunctions}
break; break;
} }
} }
startsWithBlockComment() {
this.skipTrivia();
return this.src[this.pos] === "/" && this.src[this.pos + 1] === "*";
}
next() { next() {
this.skipTrivia(); this.skipTrivia();
const { src } = this; const { src } = this;
+14 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env node #!/usr/bin/env node
// WRN editor language server source hash: 65a5536efbc7c9fee15040559bb48afe78c4686fc5e7341ffc941cc7113c8556 // WRN editor language server source hash: 4c7e59ebeb512e23d95f4169dd80da2b951ae39c31d31919994368b8e90f5cec
// WRN editor language server generator hash: f593a44aaf05495b789ce7a3086bee1eebb951b884d41c0e017bbcfe5f547e72 // WRN editor language server generator hash: f593a44aaf05495b789ce7a3086bee1eebb951b884d41c0e017bbcfe5f547e72
// @bun @bun-cjs // @bun @bun-cjs
(function(exports, require, module, __filename, __dirname) {var __create = Object.create; (function(exports, require, module, __filename, __dirname) {var __create = Object.create;
@@ -168786,6 +168786,10 @@ class Lexer {
break; break;
} }
} }
startsWithBlockComment() {
this.skipTrivia();
return this.src[this.pos] === "/" && this.src[this.pos + 1] === "*";
}
next() { next() {
this.skipTrivia(); this.skipTrivia();
const { src } = this; const { src } = this;
@@ -170521,7 +170525,12 @@ function parse(source) {
case "props": { case "props": {
lx.next(); lx.next();
expect("lbrace"); expect("lbrace");
while (lx.peek().type !== "rbrace") { while (true) {
if (lx.startsWithBlockComment()) {
throw new ParseError("Block comments are not allowed inside props {}; use // line comments instead", "WRN-PROPS-BLOCK-COMMENT");
}
if (lx.peek().type === "rbrace")
break;
const t = lx.peek(); const t = lx.peek();
if (t.type === "eof") if (t.type === "eof")
throw new ParseError("Unexpected end of input inside props"); throw new ParseError("Unexpected end of input inside props");
@@ -170880,6 +170889,9 @@ function parse(source) {
} }
expect("rbrace"); expect("rbrace");
const declaredStates = new Set(states.map((state) => state.name)); const declaredStates = new Set(states.map((state) => state.name));
if (declaredStates.has("page")) {
throw new ParseError("State name 'page' collides with the WRN 'page' keyword; choose another state name", "WRN-STATE-RESERVED-NAME");
}
for (const watcher of watches) { for (const watcher of watches) {
if (!declaredStates.has(watcher.state)) { if (!declaredStates.has(watcher.state)) {
throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`); throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`);
@@ -9,8 +9,6 @@ export interface Routes {
"/block-library": Record<string, never>; "/block-library": Record<string, never>;
"/colors": Record<string, never>; "/colors": Record<string, never>;
"/components/accordion": Record<string, never>; "/components/accordion": Record<string, never>;
"/components/advanced-date-picker": Record<string, never>;
"/components/advanced-range-slider": Record<string, never>;
"/components/advanced-select": Record<string, never>; "/components/advanced-select": Record<string, never>;
"/components/alert": Record<string, never>; "/components/alert": Record<string, never>;
"/components/announcement-bar": Record<string, never>; "/components/announcement-bar": Record<string, never>;
@@ -37,7 +35,6 @@ export interface Routes {
"/components/confetti": Record<string, never>; "/components/confetti": Record<string, never>;
"/components/container": Record<string, never>; "/components/container": Record<string, never>;
"/components/context-menu": Record<string, never>; "/components/context-menu": Record<string, never>;
"/components/copy-markup": Record<string, never>;
"/components/ctasection": Record<string, never>; "/components/ctasection": Record<string, never>;
"/components/custom-scrollbar": Record<string, never>; "/components/custom-scrollbar": Record<string, never>;
"/components/data-map": Record<string, never>; "/components/data-map": Record<string, never>;
@@ -52,7 +49,6 @@ export interface Routes {
"/components/feature-grid": Record<string, never>; "/components/feature-grid": Record<string, never>;
"/components/feature-icon-card": Record<string, never>; "/components/feature-icon-card": Record<string, never>;
"/components/file-input": Record<string, never>; "/components/file-input": Record<string, never>;
"/components/file-upload": Record<string, never>;
"/components/file-upload-progress": Record<string, never>; "/components/file-upload-progress": Record<string, never>;
"/components/footer": Record<string, never>; "/components/footer": Record<string, never>;
"/components/grid": Record<string, never>; "/components/grid": Record<string, never>;
@@ -107,8 +103,6 @@ export interface Routes {
"/components/textarea": Record<string, never>; "/components/textarea": Record<string, never>;
"/components/time-picker": Record<string, never>; "/components/time-picker": Record<string, never>;
"/components/timeline": Record<string, never>; "/components/timeline": Record<string, never>;
"/components/toast": Record<string, never>;
"/components/toast-notifications": Record<string, never>;
"/components/toaster": Record<string, never>; "/components/toaster": Record<string, never>;
"/components/toggle-count": Record<string, never>; "/components/toggle-count": Record<string, never>;
"/components/toggle-password": Record<string, never>; "/components/toggle-password": Record<string, never>;
@@ -152,8 +146,6 @@ export interface RouteNames {
"block.library": "/block-library"; "block.library": "/block-library";
"colors": "/colors"; "colors": "/colors";
"components.accordion": "/components/accordion"; "components.accordion": "/components/accordion";
"components.advanced.date.picker": "/components/advanced-date-picker";
"components.advanced.range.slider": "/components/advanced-range-slider";
"components.advanced.select": "/components/advanced-select"; "components.advanced.select": "/components/advanced-select";
"components.alert": "/components/alert"; "components.alert": "/components/alert";
"components.announcement.bar": "/components/announcement-bar"; "components.announcement.bar": "/components/announcement-bar";
@@ -180,7 +172,6 @@ export interface RouteNames {
"components.confetti": "/components/confetti"; "components.confetti": "/components/confetti";
"components.container": "/components/container"; "components.container": "/components/container";
"components.context.menu": "/components/context-menu"; "components.context.menu": "/components/context-menu";
"components.copy.markup": "/components/copy-markup";
"components.ctasection": "/components/ctasection"; "components.ctasection": "/components/ctasection";
"components.custom.scrollbar": "/components/custom-scrollbar"; "components.custom.scrollbar": "/components/custom-scrollbar";
"components.data.map": "/components/data-map"; "components.data.map": "/components/data-map";
@@ -195,7 +186,6 @@ export interface RouteNames {
"components.feature.grid": "/components/feature-grid"; "components.feature.grid": "/components/feature-grid";
"components.feature.icon.card": "/components/feature-icon-card"; "components.feature.icon.card": "/components/feature-icon-card";
"components.file.input": "/components/file-input"; "components.file.input": "/components/file-input";
"components.file.upload": "/components/file-upload";
"components.file.upload.progress": "/components/file-upload-progress"; "components.file.upload.progress": "/components/file-upload-progress";
"components.footer": "/components/footer"; "components.footer": "/components/footer";
"components.grid": "/components/grid"; "components.grid": "/components/grid";
@@ -250,8 +240,6 @@ export interface RouteNames {
"components.textarea": "/components/textarea"; "components.textarea": "/components/textarea";
"components.time.picker": "/components/time-picker"; "components.time.picker": "/components/time-picker";
"components.timeline": "/components/timeline"; "components.timeline": "/components/timeline";
"components.toast": "/components/toast";
"components.toast.notifications": "/components/toast-notifications";
"components.toaster": "/components/toaster"; "components.toaster": "/components/toaster";
"components.toggle.count": "/components/toggle-count"; "components.toggle.count": "/components/toggle-count";
"components.toggle.password": "/components/toggle-password"; "components.toggle.password": "/components/toggle-password";
@@ -364,8 +352,6 @@ export function route<N extends RouteName>(
"block.library": "/block-library", "block.library": "/block-library",
"colors": "/colors", "colors": "/colors",
"components.accordion": "/components/accordion", "components.accordion": "/components/accordion",
"components.advanced.date.picker": "/components/advanced-date-picker",
"components.advanced.range.slider": "/components/advanced-range-slider",
"components.advanced.select": "/components/advanced-select", "components.advanced.select": "/components/advanced-select",
"components.alert": "/components/alert", "components.alert": "/components/alert",
"components.announcement.bar": "/components/announcement-bar", "components.announcement.bar": "/components/announcement-bar",
@@ -392,7 +378,6 @@ export function route<N extends RouteName>(
"components.confetti": "/components/confetti", "components.confetti": "/components/confetti",
"components.container": "/components/container", "components.container": "/components/container",
"components.context.menu": "/components/context-menu", "components.context.menu": "/components/context-menu",
"components.copy.markup": "/components/copy-markup",
"components.ctasection": "/components/ctasection", "components.ctasection": "/components/ctasection",
"components.custom.scrollbar": "/components/custom-scrollbar", "components.custom.scrollbar": "/components/custom-scrollbar",
"components.data.map": "/components/data-map", "components.data.map": "/components/data-map",
@@ -407,7 +392,6 @@ export function route<N extends RouteName>(
"components.feature.grid": "/components/feature-grid", "components.feature.grid": "/components/feature-grid",
"components.feature.icon.card": "/components/feature-icon-card", "components.feature.icon.card": "/components/feature-icon-card",
"components.file.input": "/components/file-input", "components.file.input": "/components/file-input",
"components.file.upload": "/components/file-upload",
"components.file.upload.progress": "/components/file-upload-progress", "components.file.upload.progress": "/components/file-upload-progress",
"components.footer": "/components/footer", "components.footer": "/components/footer",
"components.grid": "/components/grid", "components.grid": "/components/grid",
@@ -462,8 +446,6 @@ export function route<N extends RouteName>(
"components.textarea": "/components/textarea", "components.textarea": "/components/textarea",
"components.time.picker": "/components/time-picker", "components.time.picker": "/components/time-picker",
"components.timeline": "/components/timeline", "components.timeline": "/components/timeline",
"components.toast": "/components/toast",
"components.toast.notifications": "/components/toast-notifications",
"components.toaster": "/components/toaster", "components.toaster": "/components/toaster",
"components.toggle.count": "/components/toggle-count", "components.toggle.count": "/components/toggle-count",
"components.toggle.password": "/components/toggle-password", "components.toggle.password": "/components/toggle-password",
@@ -2,6 +2,7 @@ import { mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from
import { dirname, join } from "node:path"; import { dirname, join } from "node:path";
import process from "node:process"; import process from "node:process";
import { fileURLToPath } from "node:url"; import { fileURLToPath } from "node:url";
import prettier from "prettier";
import { eventDescriptionFor, profileFor } from "./showcase-profiles.mjs"; import { eventDescriptionFor, profileFor } from "./showcase-profiles.mjs";
const exampleRoot = join(dirname(fileURLToPath(import.meta.url)), ".."); const exampleRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
@@ -1792,11 +1793,12 @@ const showcaseManifest = {
profiled: Boolean(profileFor(component.name)), profiled: Boolean(profileFor(component.name)),
})), })),
}; };
writeFileSync( const formattedManifest = await prettier.format(`${JSON.stringify(showcaseManifest, null, 2)}\n`, {
join(exampleRoot, "showcase-manifest.json"), parser: "json",
`${JSON.stringify(showcaseManifest, null, 2)}\n`, printWidth: 100,
"utf8", endOfLine: "lf",
); });
writeFileSync(join(exampleRoot, "showcase-manifest.json"), formattedManifest, "utf8");
const categoryCards = categoryEntries const categoryCards = categoryEntries
.map( .map(
File diff suppressed because it is too large Load Diff
+2
View File
@@ -7,6 +7,8 @@
"workspaces": [ "workspaces": [
"packages/*", "packages/*",
"examples/*", "examples/*",
"examples/inter-app-api-showcase/apps/*",
"examples/inter-app-api-showcase/packages/*",
"services/*" "services/*"
], ],
"scripts": { "scripts": {
+20 -10
View File
@@ -174,7 +174,7 @@ export function browserModuleRequired(ast: PageAst): boolean {
return functions.length > 0 || selectedBrowserImports(ast, functions).length > 0; return functions.length > 0 || selectedBrowserImports(ast, functions).length > 0;
} }
function functionEntry( function _functionEntry(
ast: PageAst, ast: PageAst,
fn: RuntimeFunctionDecl, fn: RuntimeFunctionDecl,
availableFunctions: string[], availableFunctions: string[],
@@ -242,7 +242,10 @@ function functionEntry(
.join(" "); .join(" ");
const peerAliases = !stateNames.length const peerAliases = !stateNames.length
? functionAliases ? functionAliases
.map((name) => `const ${name} = (...__wrnexusPeerArgs) => context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs);`) .map(
(name) =>
`const ${name} = (...__wrnexusPeerArgs) => context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs);`,
)
.join("\n") .join("\n")
: `const __wrnexusFlush = () => { ${syncStateToContext} }; : `const __wrnexusFlush = () => { ${syncStateToContext} };
const __wrnexusRestore = () => { ${syncStateFromContext} }; const __wrnexusRestore = () => { ${syncStateFromContext} };
@@ -271,9 +274,15 @@ function functionEntry(
const commitBinding = stateNames.length const commitBinding = stateNames.length
? `const __wrnexusCommit = () => { ${copyBack} }; ? `const __wrnexusCommit = () => { ${copyBack} };
${!parameterNames.has("commit") && !declaredLocals.has("commit") && !functionAliases.includes("commit") ? "const commit = __wrnexusCommit;" : ""} ${!parameterNames.has("commit") && !declaredLocals.has("commit") && !functionAliases.includes("commit") ? "const commit = __wrnexusCommit;" : ""}
${!parameterNames.has("setTimeout") && !declaredLocals.has("setTimeout") && !functionAliases.includes("setTimeout") ? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => { ${
!parameterNames.has("setTimeout") &&
!declaredLocals.has("setTimeout") &&
!functionAliases.includes("setTimeout")
? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); } try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);` : ""}` }, delay);`
: ""
}`
: ""; : "";
const body = eraseFunctionTypes(fn.body); const body = eraseFunctionTypes(fn.body);
const runtimeBindings = [ const runtimeBindings = [
@@ -312,10 +321,7 @@ export function generateBrowserModule(ast: PageAst): string {
const sharedProps = ast.props const sharedProps = ast.props
.map((entry) => entry.name) .map((entry) => entry.name)
.filter( .filter(
(name) => (name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name) && !sharedState.includes(name),
safeIdentifier(name) &&
!RUNTIME_BINDINGS.has(name) &&
!sharedState.includes(name),
); );
const callableAliases = functionNames.filter( const callableAliases = functionNames.filter(
(name) => (name) =>
@@ -362,9 +368,13 @@ function __wrnexusCreateClientFunctions(context) {
const __wrnexusCommit = () => { ${sharedCommit} }; const __wrnexusCommit = () => { ${sharedCommit} };
const __wrnexusRestore = () => { ${sharedRestore} }; const __wrnexusRestore = () => { ${sharedRestore} };
${!hasAuthoredCommit ? "const commit = __wrnexusCommit;" : ""} ${!hasAuthoredCommit ? "const commit = __wrnexusCommit;" : ""}
${!hasAuthoredSetTimeout ? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => { ${
!hasAuthoredSetTimeout
? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => {
try { return callback(...args); } finally { __wrnexusCommit(); } try { return callback(...args); } finally { __wrnexusCommit(); }
}, delay);` : ""} }, delay);`
: ""
}
const implementations = { const implementations = {
${implementations} ${implementations}
}; };
+1 -2
View File
@@ -752,8 +752,7 @@ function renderNestedComponentInvocation(
if ( if (
!attr.value.includes("{") || !attr.value.includes("{") ||
(!exprRefsState(attr.value, ctx.stateNames) && (!exprRefsState(attr.value, ctx.stateNames) && !exprRefsState(attr.value, ctx.propNames))
!exprRefsState(attr.value, ctx.propNames))
) { ) {
return rendered; return rendered;
} }
+1 -3
View File
@@ -328,9 +328,7 @@ test("stateful component keeps both prop and state text reactive", async () => {
const out = render({ start: "10", label: "Score" }); const out = render({ start: "10", label: "Score" });
expect(out).toContain('data-scope="start: 10, label: &quot;Score&quot;, count: 10"'); expect(out).toContain('data-scope="start: 10, label: &quot;Score&quot;, count: 10"');
expect(out).toContain('data-on-click="count++"'); expect(out).toContain('data-on-click="count++"');
expect(out).toContain( expect(out).toContain('<span data-text="label">Score</span>: <span data-text="count">10</span>');
'<span data-text="label">Score</span>: <span data-text="count">10</span>',
);
expect(out).toContain('data-scope="'); expect(out).toContain('data-scope="');
+4 -1
View File
@@ -89,7 +89,10 @@ const CONTROLLER_LOADER = String.raw`
/** The reactive runtime served at `/__wrnexus/reactive.js` (plain browser JS). */ /** The reactive runtime served at `/__wrnexus/reactive.js` (plain browser JS). */
export function getReactiveRuntime(development = false): string { export function getReactiveRuntime(development = false): string {
let source = stripControllerSections(runtimeForMode(development)); let source = stripControllerSections(runtimeForMode(development));
source = source.replace(" function hydrateScopes(root) {", `${CONTROLLER_LOADER}\n function hydrateScopes(root) {`); source = source.replace(
" function hydrateScopes(root) {",
`${CONTROLLER_LOADER}\n function hydrateScopes(root) {`,
);
source = source.replace( source = source.replace(
" hydrateNavbarControllers(host);\n hydratePreferenceControllers(host);\n hydrateSelectControllers(host);\n hydratePinInputControllers(host);", " hydrateNavbarControllers(host);\n hydratePreferenceControllers(host);\n hydrateSelectControllers(host);\n hydratePinInputControllers(host);",
" loadComponentControllers(host);", " loadComponentControllers(host);",
+41 -15
View File
@@ -60,7 +60,10 @@ test("split runtime hydrates a controller only from the controller asset", () =>
}); });
test("a page without controller markers does not request the controller asset", () => { test("a page without controller markers does not request the controller asset", () => {
const win = mount(`<main data-scope="count: 1"><span>{count}</span></main>`, getReactiveRuntime(true)); const win = mount(
`<main data-scope="count: 1"><span>{count}</span></main>`,
getReactiveRuntime(true),
);
expect(win.document.querySelector('script[src$="controllers.js"]')).toBeNull(); expect(win.document.querySelector('script[src$="controllers.js"]')).toBeNull();
}); });
@@ -703,20 +706,27 @@ test("a camelCase output reaches a parent binding despite attribute lowercasing"
test("development runtime warns once for an output with no parent binding", () => { test("development runtime warns once for an output with no parent binding", () => {
const win = new Window() as unknown as Window & Record<string, unknown>; const win = new Window() as unknown as Window & Record<string, unknown>;
win.document.body.innerHTML = win.document.body.innerHTML = `<div data-scope="" data-wrn-events="complete"><button data-on-click="output.complete({})">go</button></div>`;
`<div data-scope="" data-wrn-events="complete"><button data-on-click="output.complete({})">go</button></div>`;
(globalThis as Record<string, unknown>).window = win; (globalThis as Record<string, unknown>).window = win;
(globalThis as Record<string, unknown>).document = win.document; (globalThis as Record<string, unknown>).document = win.document;
(globalThis as Record<string, unknown>).location = win.location; (globalThis as Record<string, unknown>).location = win.location;
(globalThis as Record<string, unknown>).NodeFilter = (win as unknown as { NodeFilter: unknown }).NodeFilter; (globalThis as Record<string, unknown>).NodeFilter = (
(globalThis as Record<string, unknown>).MutationObserver = (win as unknown as { MutationObserver: unknown }).MutationObserver; win as unknown as { NodeFilter: unknown }
(globalThis as Record<string, unknown>).CustomEvent = (win as unknown as { CustomEvent: unknown }).CustomEvent; ).NodeFilter;
(globalThis as Record<string, unknown>).MutationObserver = (
win as unknown as { MutationObserver: unknown }
).MutationObserver;
(globalThis as Record<string, unknown>).CustomEvent = (
win as unknown as { CustomEvent: unknown }
).CustomEvent;
const warnings: unknown[][] = []; const warnings: unknown[][] = [];
const originalWarn = console.warn; const originalWarn = console.warn;
console.warn = (...args: unknown[]) => warnings.push(args); console.warn = (...args: unknown[]) => warnings.push(args);
try { try {
(0, eval)(getReactiveRuntime(true)); (0, eval)(getReactiveRuntime(true));
(win as unknown as { __wrnexusHydrateScopes?: (root: unknown) => void }).__wrnexusHydrateScopes?.(win.document); (
win as unknown as { __wrnexusHydrateScopes?: (root: unknown) => void }
).__wrnexusHydrateScopes?.(win.document);
(win.document.querySelector("button") as unknown as HTMLElement).click(); (win.document.querySelector("button") as unknown as HTMLElement).click();
(win.document.querySelector("button") as unknown as HTMLElement).click(); (win.document.querySelector("button") as unknown as HTMLElement).click();
} finally { } finally {
@@ -736,9 +746,15 @@ test("development runtime warns when a component binding names a missing functio
(globalThis as Record<string, unknown>).window = win; (globalThis as Record<string, unknown>).window = win;
(globalThis as Record<string, unknown>).document = win.document; (globalThis as Record<string, unknown>).document = win.document;
(globalThis as Record<string, unknown>).location = win.location; (globalThis as Record<string, unknown>).location = win.location;
(globalThis as Record<string, unknown>).NodeFilter = (win as unknown as { NodeFilter: unknown }).NodeFilter; (globalThis as Record<string, unknown>).NodeFilter = (
(globalThis as Record<string, unknown>).MutationObserver = (win as unknown as { MutationObserver: unknown }).MutationObserver; win as unknown as { NodeFilter: unknown }
(globalThis as Record<string, unknown>).CustomEvent = (win as unknown as { CustomEvent: unknown }).CustomEvent; ).NodeFilter;
(globalThis as Record<string, unknown>).MutationObserver = (
win as unknown as { MutationObserver: unknown }
).MutationObserver;
(globalThis as Record<string, unknown>).CustomEvent = (
win as unknown as { CustomEvent: unknown }
).CustomEvent;
const warnings: unknown[][] = []; const warnings: unknown[][] = [];
const originalWarn = console.warn; const originalWarn = console.warn;
const originalError = console.error; const originalError = console.error;
@@ -746,7 +762,9 @@ test("development runtime warns when a component binding names a missing functio
console.error = () => {}; console.error = () => {};
try { try {
(0, eval)(getReactiveRuntime(true)); (0, eval)(getReactiveRuntime(true));
(win as unknown as { __wrnexusHydrateScopes?: (root: unknown) => void }).__wrnexusHydrateScopes?.(win.document); (
win as unknown as { __wrnexusHydrateScopes?: (root: unknown) => void }
).__wrnexusHydrateScopes?.(win.document);
const target = win.document.querySelector("[data-wrn-events]") as unknown as { const target = win.document.querySelector("[data-wrn-events]") as unknown as {
__wrnexusOutputHandlers?: Record<string, Set<(payload: unknown) => unknown>>; __wrnexusOutputHandlers?: Record<string, Set<(payload: unknown) => unknown>>;
}; };
@@ -770,15 +788,23 @@ test("development runtime warns for referenced theme tokens absent from rendered
(globalThis as Record<string, unknown>).window = win; (globalThis as Record<string, unknown>).window = win;
(globalThis as Record<string, unknown>).document = win.document; (globalThis as Record<string, unknown>).document = win.document;
(globalThis as Record<string, unknown>).location = win.location; (globalThis as Record<string, unknown>).location = win.location;
(globalThis as Record<string, unknown>).NodeFilter = (win as unknown as { NodeFilter: unknown }).NodeFilter; (globalThis as Record<string, unknown>).NodeFilter = (
(globalThis as Record<string, unknown>).MutationObserver = (win as unknown as { MutationObserver: unknown }).MutationObserver; win as unknown as { NodeFilter: unknown }
(globalThis as Record<string, unknown>).CustomEvent = (win as unknown as { CustomEvent: unknown }).CustomEvent; ).NodeFilter;
(globalThis as Record<string, unknown>).MutationObserver = (
win as unknown as { MutationObserver: unknown }
).MutationObserver;
(globalThis as Record<string, unknown>).CustomEvent = (
win as unknown as { CustomEvent: unknown }
).CustomEvent;
const warnings: unknown[][] = []; const warnings: unknown[][] = [];
const originalWarn = console.warn; const originalWarn = console.warn;
console.warn = (...args: unknown[]) => warnings.push(args); console.warn = (...args: unknown[]) => warnings.push(args);
try { try {
(0, eval)(getReactiveRuntime(true)); (0, eval)(getReactiveRuntime(true));
(win as unknown as { __wrnexusHydrateScopes?: (root: unknown) => void }).__wrnexusHydrateScopes?.(win.document); (
win as unknown as { __wrnexusHydrateScopes?: (root: unknown) => void }
).__wrnexusHydrateScopes?.(win.document);
} finally { } finally {
console.warn = originalWarn; console.warn = originalWarn;
} }
@@ -31,7 +31,8 @@ test("a component nested in another component's slot keeps its boundary", async
return { render: (props: Record<string, string>) => `<b class="badge">${props.label}</b>` }; return { render: (props: Record<string, string>) => `<b class="badge">${props.label}</b>` };
} }
return { return {
default: () => '<div data-component="Card"><div data-component="Badge" label="x"></div></div>', default: () =>
'<div data-component="Card"><div data-component="Badge" label="x"></div></div>',
}; };
}, },
getMiddleware: async () => [], getMiddleware: async () => [],
+1 -3
View File
@@ -1,7 +1,5 @@
{ {
"sourceDocuments": [ "sourceDocuments": ["Screenshot-directed WRNexus UI catalog reset"],
"Screenshot-directed WRNexus UI catalog reset"
],
"components": [ "components": [
{ {
"name": "Accordion", "name": "Accordion",
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -121,7 +121,7 @@ component DataTable {
state query = "" state query = ""
state sortKey = "" state sortKey = ""
state sortDirection = "asc" state sortDirection = "asc"
state page = 1 state paginationPage = 1
state perPage = pageSize state perPage = pageSize
state selectedKeys = [] state selectedKeys = []
state remoteRows = [] state remoteRows = []
@@ -273,7 +273,7 @@ component DataTable {
// page number past the end, and a table showing nothing with rows // page number past the end, and a table showing nothing with rows
// available is worse than one that quietly lands on the last page. // available is worse than one that quietly lands on the last page.
shared function currentPage() { shared function currentPage() {
return Math.min(Math.max(1, Number(page) || 1), pageCount()) return Math.min(Math.max(1, Number(paginationPage) || 1), pageCount())
} }
shared function visibleRows() { shared function visibleRows() {
@@ -576,7 +576,7 @@ component DataTable {
sortKey = key sortKey = key
sortDirection = "asc" sortDirection = "asc"
} }
page = 1 paginationPage = 1
output.sort({ key: sortKey, direction: sortDirection }) output.sort({ key: sortKey, direction: sortDirection })
reload() reload()
output.change(viewState()) output.change(viewState())
@@ -584,7 +584,7 @@ component DataTable {
client function updateQuery(sourceEvent) { client function updateQuery(sourceEvent) {
query = sourceEvent.target.value query = sourceEvent.target.value
page = 1 paginationPage = 1
output.search({ query: query }) output.search({ query: query })
reload() reload()
output.change(viewState()) output.change(viewState())
@@ -592,7 +592,7 @@ component DataTable {
client function goToPage(next) { client function goToPage(next) {
var target = Math.min(Math.max(1, next), pageCount()) var target = Math.min(Math.max(1, next), pageCount())
page = target paginationPage = target
output.pageChange({ page: target, pageSize: Number(perPage) || 10 }) output.pageChange({ page: target, pageSize: Number(perPage) || 10 })
reload() reload()
output.change(viewState()) output.change(viewState())
@@ -602,7 +602,7 @@ component DataTable {
// takes the Dropdown select detail directly. // takes the Dropdown select detail directly.
client function pickPageSize(detail) { client function pickPageSize(detail) {
perPage = Number(detail && detail.value) || 10 perPage = Number(detail && detail.value) || 10
page = 1 paginationPage = 1
output.pageChange({ page: 1, pageSize: perPage }) output.pageChange({ page: 1, pageSize: perPage })
reload() reload()
output.change(viewState()) output.change(viewState())
@@ -613,7 +613,7 @@ component DataTable {
// clicks. // clicks.
client function clearSearch() { client function clearSearch() {
query = "" query = ""
page = 1 paginationPage = 1
output.search({ query: "" }) output.search({ query: "" })
reload() reload()
} }
+21 -5
View File
@@ -3227,7 +3227,12 @@ test("list selects items without hrefs as well as navigation items", async () =>
test("chart renders accessible SVG bars and emits point and legend outputs", async () => { test("chart renders accessible SVG bars and emits point and legend outputs", async () => {
const source = readFileSync(uiComponentPath("Chart"), "utf8"); const source = readFileSync(uiComponentPath("Chart"), "utf8");
const dom = mountHtml( const dom = mountHtml(
await renderComponent(source, { items: [{ label: "Alpha", value: 12 }, { label: "Beta", value: 6 }] }), await renderComponent(source, {
items: [
{ label: "Alpha", value: 12 },
{ label: "Beta", value: 6 },
],
}),
); );
const root = dom.querySelector('[data-ui-component="Chart"]') as HTMLElement; const root = dom.querySelector('[data-ui-component="Chart"]') as HTMLElement;
const events: string[] = []; const events: string[] = [];
@@ -3251,7 +3256,8 @@ test("tree view expands branches, selects nodes, and emits public outputs", asyn
); );
const root = dom.querySelector('[data-ui-component="TreeView"]') as HTMLElement; const root = dom.querySelector('[data-ui-component="TreeView"]') as HTMLElement;
const events: string[] = []; const events: string[] = [];
for (const name of ["toggle", "expand", "select"]) root.addEventListener(name, () => events.push(name)); for (const name of ["toggle", "expand", "select"])
root.addEventListener(name, () => events.push(name));
(root.querySelector(".wire-tree-view__toggle") as HTMLButtonElement).click(); (root.querySelector(".wire-tree-view__toggle") as HTMLButtonElement).click();
expect(root.querySelector(".wire-tree-view__group")?.getAttribute("data-show")).toBe("true"); expect(root.querySelector(".wire-tree-view__group")?.getAttribute("data-show")).toBe("true");
(root.querySelector('[aria-level="2"] .wire-tree-view__node') as HTMLButtonElement).click(); (root.querySelector('[aria-level="2"] .wire-tree-view__node') as HTMLButtonElement).click();
@@ -3259,7 +3265,12 @@ test("tree view expands branches, selects nodes, and emits public outputs", asyn
}); });
test("confetti completes deferred bursts and clipboard reports successful copies", async () => { test("confetti completes deferred bursts and clipboard reports successful copies", async () => {
const confetti = mountHtml(await renderComponent(readFileSync(uiComponentPath("Confetti"), "utf8"), { duration: 5, count: 4 })); const confetti = mountHtml(
await renderComponent(readFileSync(uiComponentPath("Confetti"), "utf8"), {
duration: 5,
count: 4,
}),
);
const confettiRoot = confetti.querySelector('[data-ui-component="Confetti"]') as HTMLElement; const confettiRoot = confetti.querySelector('[data-ui-component="Confetti"]') as HTMLElement;
const confettiEvents: string[] = []; const confettiEvents: string[] = [];
confettiRoot.addEventListener("start", () => confettiEvents.push("start")); confettiRoot.addEventListener("start", () => confettiEvents.push("start"));
@@ -3268,14 +3279,19 @@ test("confetti completes deferred bursts and clipboard reports successful copies
await new Promise((resolve) => setTimeout(resolve, 15)); await new Promise((resolve) => setTimeout(resolve, 15));
expect(confettiEvents).toEqual(["start", "complete"]); expect(confettiEvents).toEqual(["start", "complete"]);
const clipboard = mountHtml(await renderComponent(readFileSync(uiComponentPath("Clipboard"), "utf8"), { value: "npm add wrnexus" })); const clipboard = mountHtml(
await renderComponent(readFileSync(uiComponentPath("Clipboard"), "utf8"), {
value: "npm add wrnexus",
}),
);
Object.defineProperty((clipboard.window as { navigator: object }).navigator, "clipboard", { Object.defineProperty((clipboard.window as { navigator: object }).navigator, "clipboard", {
configurable: true, configurable: true,
value: { writeText: () => Promise.resolve() }, value: { writeText: () => Promise.resolve() },
}); });
const clipboardRoot = clipboard.querySelector('[data-ui-component="Clipboard"]') as HTMLElement; const clipboardRoot = clipboard.querySelector('[data-ui-component="Clipboard"]') as HTMLElement;
const clipboardEvents: string[] = []; const clipboardEvents: string[] = [];
for (const name of ["copy", "success"]) clipboardRoot.addEventListener(name, () => clipboardEvents.push(name)); for (const name of ["copy", "success"])
clipboardRoot.addEventListener(name, () => clipboardEvents.push(name));
(clipboardRoot.querySelector("button") as HTMLButtonElement).click(); (clipboardRoot.querySelector("button") as HTMLButtonElement).click();
await new Promise((resolve) => setTimeout(resolve, 0)); await new Promise((resolve) => setTimeout(resolve, 0));
expect(clipboardEvents).toEqual(["copy", "success"]); expect(clipboardEvents).toEqual(["copy", "success"]);
+7 -3
View File
@@ -1,5 +1,6 @@
import { readdirSync, readFileSync, writeFileSync } from "node:fs"; import { readdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path"; import { join } from "node:path";
import prettier from "prettier";
const uiRoot = join(import.meta.dirname, "..", "packages", "ui"); const uiRoot = join(import.meta.dirname, "..", "packages", "ui");
const componentsDir = join(uiRoot, "components"); const componentsDir = join(uiRoot, "components");
@@ -11,17 +12,20 @@ function normalizeNewlines(source) {
return source.replace(/\r\n?/g, "\n"); return source.replace(/\r\n?/g, "\n");
} }
async function writeFormatted(path, source) { async function writeFormatted(path, source, parser) {
const formatted = parser
? await prettier.format(source, { parser, printWidth: 100, endOfLine: "lf" })
: source;
const current = readFileSync(path, "utf8"); const current = readFileSync(path, "utf8");
// Do not rewrite a generated file when only its working-tree line endings // Do not rewrite a generated file when only its working-tree line endings
// differ. This keeps release verification clean on Windows CRLF checkouts // differ. This keeps release verification clean on Windows CRLF checkouts
// while still rewriting files whose generated content is genuinely stale. // while still rewriting files whose generated content is genuinely stale.
if (normalizeNewlines(current) === normalizeNewlines(source)) { if (normalizeNewlines(current) === normalizeNewlines(formatted)) {
return false; return false;
} }
writeFileSync(path, source); writeFileSync(path, formatted);
return true; return true;
} }