From 51286d0fa368e111d6f7ce0904e9933a89fc973f Mon Sep 17 00:00:00 2001 From: Ajay Ghanwat Date: Sun, 9 Aug 2026 14:39:22 +0530 Subject: [PATCH] complete framework remediation validation --- bun.lock | 235 +++++- docs/framework-remediation-plan.md | 12 + docs/ui-visual-contract-0.8.json | 2 +- editors/vscode/src/compiler.cjs | 198 +++-- editors/vscode/src/extension.bundle.cjs | 166 ++-- editors/vscode/src/language-server.cjs | 16 +- examples/component-showcase/app/routes.gen.ts | 18 - .../scripts/generate-showcase.mjs | 12 +- .../component-showcase/showcase-manifest.json | 775 ++++-------------- package.json | 2 + packages/compiler/src/client-codegen.ts | 30 +- packages/compiler/src/codegen.ts | 3 +- packages/compiler/test/compiler.test.ts | 4 +- packages/csr/src/index.ts | 5 +- packages/csr/test/reactive.test.ts | 62 +- .../component-composition-runtime.test.ts | 3 +- packages/ui/component-catalog.json | 4 +- packages/ui/component-reference.json | 775 ++++-------------- packages/ui/components/DataTable.wrn | 14 +- packages/ui/test/ui.test.ts | 26 +- scripts/generate-ui-component-reference.mjs | 10 +- 21 files changed, 898 insertions(+), 1474 deletions(-) diff --git a/bun.lock b/bun.lock index 1d44ccec..8f319ed4 100644 --- a/bun.lock +++ b/bun.lock @@ -109,12 +109,101 @@ "name": "inter-app-api-showcase", "devDependencies": { "@eslint/js": "^9.0.0", - "@types/bun": "latest", + "@types/bun": "^1.3.14", "@wrnexus/cli": "0.8.6", "eslint": "^9.0.0", - "prettier": "latest", + "prettier": "^3.9.6", "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": { @@ -563,7 +652,7 @@ }, "services/managed-captcha": { "name": "@wrnexus/managed-captcha-service", - "version": "0.8.0", + "version": "0.8.6", "dependencies": { "@wrnexus/captcha": "workspace:*", }, @@ -580,6 +669,8 @@ "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=="], + "@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=="], "@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=="], + "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=="], "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=="], + "web": ["web@workspace:examples/inter-app-api-showcase/apps/web"], + "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=="], @@ -1318,6 +1413,12 @@ "@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=="], "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=="], + "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=="], + "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=="], "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=="], + "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/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=="], + "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/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/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=="], } } diff --git a/docs/framework-remediation-plan.md b/docs/framework-remediation-plan.md index 85f153f2..3682c1d8 100644 --- a/docs/framework-remediation-plan.md +++ b/docs/framework-remediation-plan.md @@ -1,5 +1,17 @@ # 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 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 diff --git a/docs/ui-visual-contract-0.8.json b/docs/ui-visual-contract-0.8.json index df205aed..e82a3bf5 100644 --- a/docs/ui-visual-contract-0.8.json +++ b/docs/ui-visual-contract-0.8.json @@ -27,7 +27,7 @@ "packages/ui/components/ContextMenu.wrn": "33fb0f60268b12411d66e3031dc0557cb231149e7a8d83340b4b453a6e37cb09", "packages/ui/components/CustomScrollbar.wrn": "fedb2ab06cc2cf9499c130590945ca6971a3edfb60407b6658ef7756e4be9823", "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/DeviceFrame.wrn": "1151090854901710971808f42dd2f1dcbd102e6afef63a5afecd01d4b3f0797d", "packages/ui/components/Divider.wrn": "f5cc449611022b3d3eedf982ae48f6b1a289db7855cc9b6ea0248dcda807ffb3", diff --git a/editors/vscode/src/compiler.cjs b/editors/vscode/src/compiler.cjs index c57f4db3..a102f229 100644 --- a/editors/vscode/src/compiler.cjs +++ b/editors/vscode/src/compiler.cjs @@ -1,6 +1,6 @@ "use strict"; // 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 // Generated with TypeScript: 5.9.3 const __nodeRequire = require; @@ -558,7 +558,7 @@ function browserModuleRequired(ast) { const functions = ast.runtimeFunctions.filter((fn) => ["legacy", "client", "shared"].includes(fn.runtime)); 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)); /* * Names the function body declares for itself. @@ -608,32 +608,42 @@ function functionEntry(ast, fn, availableFunctions) { const syncStateFromContext = stateNames .map((name) => `${name} = context.state.${name};`) .join(" "); - const peerAliases = functionAliases - .map((name) => { - const call = `context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs)`; - if (!stateNames.length) { - return `const ${name} = (...__wrnexusPeerArgs) => ${call};`; - } - return `const ${name} = (...__wrnexusPeerArgs) => { - ${syncStateToContext} - let __wrnexusPeerResult; + const peerAliases = !stateNames.length + ? functionAliases + .map((name) => `const ${name} = (...__wrnexusPeerArgs) => context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs);`) + .join("\n") + : `const __wrnexusFlush = () => { ${syncStateToContext} }; + const __wrnexusRestore = () => { ${syncStateFromContext} }; + const __wrnexusPeer = (name, args) => { + __wrnexusFlush(); + let result; try { - __wrnexusPeerResult = ${call}; - } catch (__wrnexusPeerError) { - ${syncStateFromContext} - throw __wrnexusPeerError; + result = context.functions[name](...args); + } catch (error) { + __wrnexusRestore(); + throw error; } - if (__wrnexusPeerResult && typeof __wrnexusPeerResult.then === "function") { - return Promise.resolve(__wrnexusPeerResult).finally(() => { ${syncStateFromContext} }); + if (result && typeof result.then === "function") { + return Promise.resolve(result).finally(__wrnexusRestore); } - ${syncStateFromContext} - return __wrnexusPeerResult; - };`; - }) - .join("\n"); + __wrnexusRestore(); + return result; + }; + ${functionAliases.map((name) => `const ${name} = (...__wrnexusPeerArgs) => __wrnexusPeer(${JSON.stringify(name)}, __wrnexusPeerArgs);`).join("\n")}`; const copyBack = stateNames .map((name) => `if (!Object.is(${name}, __wrnexusInitialState[${JSON.stringify(name)}])) context.state.${name} = ${name};`) .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 runtimeBindings = [ !parameterNames.has("output") ? "const output = context.output;" : "", @@ -647,12 +657,13 @@ function functionEntry(ast, fn, availableFunctions) { ${initialStateSnapshot} ${stateAliases} ${propAliases} + ${commitBinding} ${peerAliases} ${runtimeBindings} try { ${body} } finally { - ${copyBack} + ${stateNames.length ? "__wrnexusCommit();" : ""} } }`; } @@ -663,22 +674,74 @@ function generateBrowserModule(ast) { const selectedImports = selectedBrowserImports(ast, functions); const imports = selectedImports.map((entry) => entry.code).join("\n"); 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} ${imports} 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 __wrnexusOutputs = ${JSON.stringify(ast.outputs)}; 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 scopedContext = { ...context, functions }; - for (const [name, handler] of Object.entries(__wrnexusClientFunctions)) { - functions[name] = (...args) => handler(scopedContext, ...args); + for (const name of Object.keys(implementations)) { + functions[name] = (...args) => { + __wrnexusRestore(); + return implementations[name](...args); + }; } 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)})}` : compileAttrValue(attr.value, ctx); 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; } 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(""); const loops = loopVarsOf(node); @@ -2178,7 +2240,9 @@ function exprRefsState(expr, stateNames) { return false; } 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) { return nodes.some((node) => { @@ -2242,6 +2306,9 @@ function compileText(raw, ctx) { // list renderer fills it per item; it has no server-side value. out += escLit(`{${expr}}`); } + else if (expr === "content") { + out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`; + } else if (exprRefsComponentReactiveValue(expr, ctx)) { // 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 @@ -2251,9 +2318,6 @@ function compileText(raw, ctx) { `\${__wireHtml(${ctx.resolveExpr(expr)})}` + escLit(``); } - else if (expr === "content") { - out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`; - } else { out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`; } @@ -2593,6 +2657,7 @@ function generateComponent(ast) { }; const ctx = { stateNames, + propNames: new Set(effectiveProps.map((entry) => entry.name)), functionNames: new Set(ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name)), resolveExpr, eventNames: publicOutputNames(ast), @@ -2610,12 +2675,12 @@ function generateComponent(ast) { .join(""); const styles = ast.styles.map((body) => body.trim()).filter(Boolean); const styleTag = escLit(localStyleTag(ast, styles)); - // A component needs a reactive scope only when it has state or event handlers. - // Prop-driven text/attributes are baked server-side, so static components ship - // no JavaScript at all. + // Props remain server-rendered and also become signals so a parent can drive + // a mounted child after hydration. const behavior = componentBehavior(ast); const needsScope = ast.runtime !== "server" && - (browserStates.length > 0 || + (effectiveProps.length > 0 || + browserStates.length > 0 || ast.computed.length > 0 || viewHasEvents(ast.view) || behavior !== null); @@ -2632,7 +2697,7 @@ function generateComponent(ast) { 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(` 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")) { 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;`) .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) { return def; } @@ -2722,14 +2787,14 @@ function generateComponent(ast) { if (typeof v === "string") { try { 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 { - if (declared === "array") throw new TypeError("Expected an array prop"); - return def; + throw new TypeError("Expected an array prop '" + propName + "'"); } } - return def; + throw new TypeError("Expected an array prop '" + propName + "'"); } if (declared === "object" || (def !== null && typeof def === "object")) { @@ -2745,20 +2810,16 @@ function generateComponent(ast) { try { const parsed = JSON.parse(v); - return ( - parsed !== null && - typeof parsed === "object" && - !Array.isArray(parsed) - ) - ? parsed - : def; + if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) { + throw new TypeError("Expected an object prop '" + propName + "'"); + } + return parsed; } catch { - if (declared === "object") throw new TypeError("Expected an object prop"); - return def; + throw new TypeError("Expected an object prop '" + propName + "'"); } } - return def; + throw new TypeError("Expected an object prop '" + propName + "'"); } if (declared === "bigint") return BigInt(v); @@ -2828,10 +2889,12 @@ function __wireSpreadAttrs(value: any): string { lowerName === "style" || lowerName === "slot" || lowerName === "data-component" || - // Internal markers must not leak through a spread -- except the - // parent's output handlers, whose whole job is to ride from the mount - // onto the view root so the mounting scope can bind them there. - (lowerName.startsWith("data-wrn") && !lowerName.startsWith("data-wrn-out-")) + // Internal markers must not leak through a spread. Parent-owned output + // and prop bindings ride from the mount onto the + // rendered child root so the mounting scope can bind them there. + (lowerName.startsWith("data-wrn") && + !lowerName.startsWith("data-wrn-out-") && + !lowerName.startsWith("data-wrn-prop-bind-")) ) { continue; } @@ -5634,7 +5697,12 @@ function parse(source) { // props { name: Type = ; @event name = function } lx.next(); 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(); if (t.type === "eof") throw new ParseError("Unexpected end of input inside props"); @@ -6013,6 +6081,9 @@ function parse(source) { } expect("rbrace"); 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) { if (!declaredStates.has(watcher.state)) { throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`); @@ -6543,6 +6614,11 @@ class Lexer { 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. */ next() { this.skipTrivia(); diff --git a/editors/vscode/src/extension.bundle.cjs b/editors/vscode/src/extension.bundle.cjs index fc44a3de..1c31bc6a 100644 --- a/editors/vscode/src/extension.bundle.cjs +++ b/editors/vscode/src/extension.bundle.cjs @@ -1,4 +1,4 @@ -// WRN editor extension source hash: 6165420f37af57e441086efeb6b25528f72e77a39abb2c76ca5bc8748dd90c2f +// WRN editor extension source hash: c09cc127dcc7fbae562648b09435fb96134c18e63ba21d7a4b476b916f4a8256 // WRN editor extension generator hash: 456d1d614e44e5fb1f19b784176c09cf2ade9b64ef73a17934c2698150b62728 "use strict"; 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)); 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 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)) { @@ -23220,30 +23220,33 @@ ${(0, codegen_ts_1.generate)(ast)}`, const propAliases = propNames.length ? `const { ${propNames.join(", ")} } = context.props;` : ""; const syncStateToContext = stateNames.map((name) => `context.state.${name} = ${name};`).join(" "); const syncStateFromContext = stateNames.map((name) => `${name} = context.state.${name};`).join(" "); - const peerAliases = functionAliases.map((name) => { - const call = `context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs)`; - if (!stateNames.length) { - return `const ${name} = (...__wrnexusPeerArgs) => ${call};`; - } - return `const ${name} = (...__wrnexusPeerArgs) => { - ${syncStateToContext} - let __wrnexusPeerResult; + const peerAliases = !stateNames.length ? functionAliases.map((name) => `const ${name} = (...__wrnexusPeerArgs) => context.functions[${JSON.stringify(name)}](...__wrnexusPeerArgs);`).join(` +`) : `const __wrnexusFlush = () => { ${syncStateToContext} }; + const __wrnexusRestore = () => { ${syncStateFromContext} }; + const __wrnexusPeer = (name, args) => { + __wrnexusFlush(); + let result; try { - __wrnexusPeerResult = ${call}; - } catch (__wrnexusPeerError) { - ${syncStateFromContext} - throw __wrnexusPeerError; + result = context.functions[name](...args); + } catch (error) { + __wrnexusRestore(); + throw error; } - if (__wrnexusPeerResult && typeof __wrnexusPeerResult.then === "function") { - return Promise.resolve(__wrnexusPeerResult).finally(() => { ${syncStateFromContext} }); + if (result && typeof result.then === "function") { + return Promise.resolve(result).finally(__wrnexusRestore); } - ${syncStateFromContext} - return __wrnexusPeerResult; - };`; - }).join(` -`); + __wrnexusRestore(); + return result; + }; + ${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 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 runtimeBindings = [ !parameterNames.has("output") ? "const output = context.output;" : "", @@ -23256,12 +23259,13 @@ ${(0, codegen_ts_1.generate)(ast)}`, ${initialStateSnapshot} ${stateAliases} ${propAliases} + ${commitBinding} ${peerAliases} ${runtimeBindings} try { ${body} } finally { - ${copyBack} + ${stateNames.length ? "__wrnexusCommit();" : ""} } }`; } @@ -23273,23 +23277,66 @@ ${(0, codegen_ts_1.generate)(ast)}`, const imports = selectedImports.map((entry) => entry.code).join(` `); 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} ${imports} 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 __wrnexusOutputs = ${JSON.stringify(ast.outputs)}; 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 scopedContext = { ...context, functions }; - for (const [name, handler] of Object.entries(__wrnexusClientFunctions)) { - functions[name] = (...args) => handler(scopedContext, ...args); + for (const name of Object.keys(implementations)) { + functions[name] = (...args) => { + __wrnexusRestore(); + return implementations[name](...args); + }; } 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 compiledValue = wholeExpression ? `\${__wireProp(${ctx.resolveExpr(wholeExpression)})}` : compileAttrValue(attr.value, ctx); 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; } 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(""); const loops = loopVarsOf(node); const childCtx = loops.length > 0 ? { @@ -24547,7 +24594,7 @@ ${handlers.join(` return false; } 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) { return nodes.some((node) => { @@ -24599,10 +24646,10 @@ ${handlers.join(` out += escLit(``); } else if (ctx.loopVars && exprRefsState(expr, ctx.loopVars)) { out += escLit(`{${expr}}`); - } else if (exprRefsComponentReactiveValue(expr, ctx)) { - out += escLit(``) + `\${__wireHtml(${ctx.resolveExpr(expr)})}` + escLit(``); } else if (expr === "content") { out += `\${__wireRaw(${ctx.resolveExpr(expr)})}`; + } else if (exprRefsComponentReactiveValue(expr, ctx)) { + out += escLit(``) + `\${__wireHtml(${ctx.resolveExpr(expr)})}` + escLit(``); } else { out += `\${__wireHtml(${ctx.resolveExpr(expr)})}`; } @@ -24855,6 +24902,7 @@ ${handlers.join(` }; const ctx = { stateNames, + propNames: new Set(effectiveProps.map((entry) => entry.name)), functionNames: new Set(ast.runtimeFunctions.filter((fn) => fn.runtime !== "server").map((fn) => fn.name)), resolveExpr, eventNames: publicOutputNames(ast) @@ -24867,7 +24915,7 @@ ${handlers.join(` const styles = ast.styles.map((body) => body.trim()).filter(Boolean); const styleTag = escLit(localStyleTag(ast, styles)); 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) { out.push(`import { Buffer as __WrnexusBuffer } from "node:buffer";`); } @@ -24881,7 +24929,7 @@ ${handlers.join(` 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(` 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")) { 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) { return def; } @@ -24966,14 +25014,14 @@ ${ast.outputs.map((output) => ` ${JSON.stringify(output.name)}(${output.payload if (typeof v === "string") { try { 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 { - if (declared === "array") throw new TypeError("Expected an array prop"); - return def; + throw new TypeError("Expected an array prop '" + propName + "'"); } } - return def; + throw new TypeError("Expected an array prop '" + propName + "'"); } if (declared === "object" || (def !== null && typeof def === "object")) { @@ -24989,20 +25037,16 @@ ${ast.outputs.map((output) => ` ${JSON.stringify(output.name)}(${output.payload try { const parsed = JSON.parse(v); - return ( - parsed !== null && - typeof parsed === "object" && - !Array.isArray(parsed) - ) - ? parsed - : def; + if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) { + throw new TypeError("Expected an object prop '" + propName + "'"); + } + return parsed; } catch { - if (declared === "object") throw new TypeError("Expected an object prop"); - return def; + throw new TypeError("Expected an object prop '" + propName + "'"); } } - return def; + throw new TypeError("Expected an object prop '" + propName + "'"); } if (declared === "bigint") return BigInt(v); @@ -25072,10 +25116,12 @@ function __wireSpreadAttrs(value: any): string { lowerName === "style" || lowerName === "slot" || lowerName === "data-component" || - // Internal markers must not leak through a spread -- except the - // parent's output handlers, whose whole job is to ride from the mount - // onto the view root so the mounting scope can bind them there. - (lowerName.startsWith("data-wrn") && !lowerName.startsWith("data-wrn-out-")) + // Internal markers must not leak through a spread. Parent-owned output + // and prop bindings ride from the mount onto the + // rendered child root so the mounting scope can bind them there. + (lowerName.startsWith("data-wrn") && + !lowerName.startsWith("data-wrn-out-") && + !lowerName.startsWith("data-wrn-prop-bind-")) ) { continue; } @@ -27916,7 +27962,12 @@ ${serverFunctions} case "props": { lx.next(); 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(); if (t.type === "eof") throw new ParseError("Unexpected end of input inside props"); @@ -28275,6 +28326,9 @@ ${serverFunctions} } expect("rbrace"); 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) { if (!declaredStates.has(watcher.state)) { throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`); @@ -28748,6 +28802,10 @@ ${serverFunctions} break; } } + startsWithBlockComment() { + this.skipTrivia(); + return this.src[this.pos] === "/" && this.src[this.pos + 1] === "*"; + } next() { this.skipTrivia(); const { src } = this; diff --git a/editors/vscode/src/language-server.cjs b/editors/vscode/src/language-server.cjs index b7ca2a14..67e760ac 100644 --- a/editors/vscode/src/language-server.cjs +++ b/editors/vscode/src/language-server.cjs @@ -1,5 +1,5 @@ #!/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 // @bun @bun-cjs (function(exports, require, module, __filename, __dirname) {var __create = Object.create; @@ -168786,6 +168786,10 @@ class Lexer { break; } } + startsWithBlockComment() { + this.skipTrivia(); + return this.src[this.pos] === "/" && this.src[this.pos + 1] === "*"; + } next() { this.skipTrivia(); const { src } = this; @@ -170521,7 +170525,12 @@ function parse(source) { case "props": { lx.next(); 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(); if (t.type === "eof") throw new ParseError("Unexpected end of input inside props"); @@ -170880,6 +170889,9 @@ function parse(source) { } expect("rbrace"); 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) { if (!declaredStates.has(watcher.state)) { throw new ParseError(`Cannot watch undeclared state '${watcher.state}'`); diff --git a/examples/component-showcase/app/routes.gen.ts b/examples/component-showcase/app/routes.gen.ts index 4690813f..a16c82c6 100644 --- a/examples/component-showcase/app/routes.gen.ts +++ b/examples/component-showcase/app/routes.gen.ts @@ -9,8 +9,6 @@ export interface Routes { "/block-library": Record; "/colors": Record; "/components/accordion": Record; - "/components/advanced-date-picker": Record; - "/components/advanced-range-slider": Record; "/components/advanced-select": Record; "/components/alert": Record; "/components/announcement-bar": Record; @@ -37,7 +35,6 @@ export interface Routes { "/components/confetti": Record; "/components/container": Record; "/components/context-menu": Record; - "/components/copy-markup": Record; "/components/ctasection": Record; "/components/custom-scrollbar": Record; "/components/data-map": Record; @@ -52,7 +49,6 @@ export interface Routes { "/components/feature-grid": Record; "/components/feature-icon-card": Record; "/components/file-input": Record; - "/components/file-upload": Record; "/components/file-upload-progress": Record; "/components/footer": Record; "/components/grid": Record; @@ -107,8 +103,6 @@ export interface Routes { "/components/textarea": Record; "/components/time-picker": Record; "/components/timeline": Record; - "/components/toast": Record; - "/components/toast-notifications": Record; "/components/toaster": Record; "/components/toggle-count": Record; "/components/toggle-password": Record; @@ -152,8 +146,6 @@ export interface RouteNames { "block.library": "/block-library"; "colors": "/colors"; "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.alert": "/components/alert"; "components.announcement.bar": "/components/announcement-bar"; @@ -180,7 +172,6 @@ export interface RouteNames { "components.confetti": "/components/confetti"; "components.container": "/components/container"; "components.context.menu": "/components/context-menu"; - "components.copy.markup": "/components/copy-markup"; "components.ctasection": "/components/ctasection"; "components.custom.scrollbar": "/components/custom-scrollbar"; "components.data.map": "/components/data-map"; @@ -195,7 +186,6 @@ export interface RouteNames { "components.feature.grid": "/components/feature-grid"; "components.feature.icon.card": "/components/feature-icon-card"; "components.file.input": "/components/file-input"; - "components.file.upload": "/components/file-upload"; "components.file.upload.progress": "/components/file-upload-progress"; "components.footer": "/components/footer"; "components.grid": "/components/grid"; @@ -250,8 +240,6 @@ export interface RouteNames { "components.textarea": "/components/textarea"; "components.time.picker": "/components/time-picker"; "components.timeline": "/components/timeline"; - "components.toast": "/components/toast"; - "components.toast.notifications": "/components/toast-notifications"; "components.toaster": "/components/toaster"; "components.toggle.count": "/components/toggle-count"; "components.toggle.password": "/components/toggle-password"; @@ -364,8 +352,6 @@ export function route( "block.library": "/block-library", "colors": "/colors", "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.alert": "/components/alert", "components.announcement.bar": "/components/announcement-bar", @@ -392,7 +378,6 @@ export function route( "components.confetti": "/components/confetti", "components.container": "/components/container", "components.context.menu": "/components/context-menu", - "components.copy.markup": "/components/copy-markup", "components.ctasection": "/components/ctasection", "components.custom.scrollbar": "/components/custom-scrollbar", "components.data.map": "/components/data-map", @@ -407,7 +392,6 @@ export function route( "components.feature.grid": "/components/feature-grid", "components.feature.icon.card": "/components/feature-icon-card", "components.file.input": "/components/file-input", - "components.file.upload": "/components/file-upload", "components.file.upload.progress": "/components/file-upload-progress", "components.footer": "/components/footer", "components.grid": "/components/grid", @@ -462,8 +446,6 @@ export function route( "components.textarea": "/components/textarea", "components.time.picker": "/components/time-picker", "components.timeline": "/components/timeline", - "components.toast": "/components/toast", - "components.toast.notifications": "/components/toast-notifications", "components.toaster": "/components/toaster", "components.toggle.count": "/components/toggle-count", "components.toggle.password": "/components/toggle-password", diff --git a/examples/component-showcase/scripts/generate-showcase.mjs b/examples/component-showcase/scripts/generate-showcase.mjs index 249dc2ab..0a43b0b3 100644 --- a/examples/component-showcase/scripts/generate-showcase.mjs +++ b/examples/component-showcase/scripts/generate-showcase.mjs @@ -2,6 +2,7 @@ import { mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from import { dirname, join } from "node:path"; import process from "node:process"; import { fileURLToPath } from "node:url"; +import prettier from "prettier"; import { eventDescriptionFor, profileFor } from "./showcase-profiles.mjs"; const exampleRoot = join(dirname(fileURLToPath(import.meta.url)), ".."); @@ -1792,11 +1793,12 @@ const showcaseManifest = { profiled: Boolean(profileFor(component.name)), })), }; -writeFileSync( - join(exampleRoot, "showcase-manifest.json"), - `${JSON.stringify(showcaseManifest, null, 2)}\n`, - "utf8", -); +const formattedManifest = await prettier.format(`${JSON.stringify(showcaseManifest, null, 2)}\n`, { + parser: "json", + printWidth: 100, + endOfLine: "lf", +}); +writeFileSync(join(exampleRoot, "showcase-manifest.json"), formattedManifest, "utf8"); const categoryCards = categoryEntries .map( diff --git a/examples/component-showcase/showcase-manifest.json b/examples/component-showcase/showcase-manifest.json index 07caa776..577c17b4 100644 --- a/examples/component-showcase/showcase-manifest.json +++ b/examples/component-showcase/showcase-manifest.json @@ -13,11 +13,7 @@ "demoCount": 3, "propCount": 17, "slots": [], - "events": [ - "change", - "open", - "close" - ], + "events": ["change", "open", "close"], "profiled": false }, { @@ -29,16 +25,7 @@ "demoCount": 41, "propCount": 51, "slots": [], - "events": [ - "search", - "select", - "change", - "clear", - "open", - "close", - "load", - "error" - ], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], "profiled": false }, { @@ -50,10 +37,7 @@ "demoCount": 3, "propCount": 21, "slots": [], - "events": [ - "dismiss", - "action" - ], + "events": ["dismiss", "action"], "profiled": false }, { @@ -65,9 +49,7 @@ "demoCount": 3, "propCount": 19, "slots": [], - "events": [ - "dismiss" - ], + "events": ["dismiss"], "profiled": true }, { @@ -78,16 +60,8 @@ "purpose": "Reusable auth form component.", "demoCount": 3, "propCount": 13, - "slots": [ - "default" - ], - "events": [ - "submit", - "change", - "input", - "focus", - "blur" - ], + "slots": ["default"], + "events": ["submit", "change", "input", "focus", "blur"], "profiled": false }, { @@ -98,10 +72,7 @@ "purpose": "Reusable auth split layout component.", "demoCount": 3, "propCount": 8, - "slots": [ - "aside-extra", - "form" - ], + "slots": ["aside-extra", "form"], "events": [], "profiled": false }, @@ -114,11 +85,7 @@ "demoCount": 3, "propCount": 18, "slots": [], - "events": [ - "load", - "error", - "click" - ], + "events": ["load", "error", "click"], "profiled": false }, { @@ -130,9 +97,7 @@ "demoCount": 3, "propCount": 12, "slots": [], - "events": [ - "overflow" - ], + "events": ["overflow"], "profiled": false }, { @@ -156,9 +121,7 @@ "demoCount": 3, "propCount": 22, "slots": [], - "events": [ - "dismiss" - ], + "events": ["dismiss"], "profiled": false }, { @@ -169,9 +132,7 @@ "purpose": "Theme-aware, responsive blockquote component.", "demoCount": 3, "propCount": 13, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": false }, @@ -184,9 +145,7 @@ "demoCount": 3, "propCount": 12, "slots": [], - "events": [ - "select" - ], + "events": ["select"], "profiled": true }, { @@ -197,14 +156,8 @@ "purpose": "Theme-aware, responsive button component.", "demoCount": 8, "propCount": 25, - "slots": [ - "default" - ], - "events": [ - "click", - "focus", - "blur" - ], + "slots": ["default"], + "events": ["click", "focus", "blur"], "profiled": false }, { @@ -215,14 +168,8 @@ "purpose": "Theme-aware, responsive button group component.", "demoCount": 3, "propCount": 13, - "slots": [ - "default" - ], - "events": [ - "click", - "select", - "change" - ], + "slots": ["default"], + "events": ["click", "select", "change"], "profiled": false }, { @@ -233,12 +180,7 @@ "purpose": "Close a page or major section with conversion-focused copy, actions, and optional supporting visual content.", "demoCount": 3, "propCount": 25, - "slots": [ - "default", - "actions", - "visual", - "footer" - ], + "slots": ["default", "actions", "visual", "footer"], "events": [], "profiled": true }, @@ -250,17 +192,8 @@ "purpose": "Group related content in a responsive themed surface with title, description, content, and supporting slots.", "demoCount": 3, "propCount": 31, - "slots": [ - "default" - ], - "events": [ - "click", - "action", - "navigate", - "dismiss", - "load", - "error" - ], + "slots": ["default"], + "events": ["click", "action", "navigate", "dismiss", "load", "error"], "profiled": true }, { @@ -271,9 +204,7 @@ "purpose": "Theme-aware, responsive carousel component.", "demoCount": 3, "propCount": 22, - "slots": [ - "default" - ], + "slots": ["default"], "events": [ "initialize", "change", @@ -296,14 +227,8 @@ "purpose": "Theme-aware, responsive chart component.", "demoCount": 3, "propCount": 12, - "slots": [ - "default" - ], - "events": [ - "select", - "dataPointClick", - "legendToggle" - ], + "slots": ["default"], + "events": ["select", "dataPointClick", "legendToggle"], "profiled": false }, { @@ -314,15 +239,8 @@ "purpose": "Theme-aware, responsive chat bubble component.", "demoCount": 3, "propCount": 11, - "slots": [ - "default" - ], - "events": [ - "action", - "messageClick", - "avatarClick", - "linkClick" - ], + "slots": ["default"], + "events": ["action", "messageClick", "avatarClick", "linkClick"], "profiled": false }, { @@ -333,16 +251,8 @@ "purpose": "Theme-aware, responsive checkbox component.", "demoCount": 3, "propCount": 27, - "slots": [ - "default" - ], - "events": [ - "input", - "change", - "focus", - "blur", - "invalid" - ], + "slots": ["default"], + "events": ["input", "change", "focus", "blur", "invalid"], "profiled": false }, { @@ -353,14 +263,8 @@ "purpose": "Theme-aware, responsive clipboard component.", "demoCount": 3, "propCount": 11, - "slots": [ - "default" - ], - "events": [ - "copy", - "success", - "error" - ], + "slots": ["default"], + "events": ["copy", "success", "error"], "profiled": false }, { @@ -371,14 +275,8 @@ "purpose": "Theme-aware, responsive collapse component.", "demoCount": 3, "propCount": 8, - "slots": [ - "default" - ], - "events": [ - "toggle", - "open", - "close" - ], + "slots": ["default"], + "events": ["toggle", "open", "close"], "profiled": false }, { @@ -390,12 +288,7 @@ "demoCount": 3, "propCount": 19, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur" - ], + "events": ["input", "change", "focus", "blur"], "profiled": false }, { @@ -406,9 +299,7 @@ "purpose": "Create responsive balanced content columns with configurable count, gap, density, and maximum width.", "demoCount": 3, "propCount": 6, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -421,16 +312,7 @@ "demoCount": 21, "propCount": 41, "slots": [], - "events": [ - "search", - "select", - "change", - "clear", - "open", - "close", - "load", - "error" - ], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], "profiled": false }, { @@ -441,13 +323,8 @@ "purpose": "Theme-aware, responsive confetti component.", "demoCount": 3, "propCount": 8, - "slots": [ - "default" - ], - "events": [ - "start", - "complete" - ], + "slots": ["default"], + "events": ["start", "complete"], "profiled": false }, { @@ -458,9 +335,7 @@ "purpose": "Constrain and align page content with responsive gutters and compact, wide, or full width options.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -472,18 +347,8 @@ "purpose": "Open an accessible keyboard-aware action menu from pointer or keyboard context interactions.", "demoCount": 3, "propCount": 18, - "slots": [ - "trigger", - "header", - "default", - "footer" - ], - "events": [ - "open", - "close", - "select", - "action" - ], + "slots": ["trigger", "header", "default", "footer"], + "events": ["open", "close", "select", "action"], "profiled": true }, { @@ -494,9 +359,7 @@ "purpose": "Theme-aware, responsive custom scrollbar component.", "demoCount": 2, "propCount": 7, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -508,13 +371,8 @@ "purpose": "Theme-aware, responsive data map component.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "select", - "change" - ], + "slots": ["default"], + "events": ["select", "change"], "profiled": false }, { @@ -525,9 +383,7 @@ "purpose": "Sortable, filterable, paginated data table with row selection.", "demoCount": 9, "propCount": 29, - "slots": [ - "default" - ], + "slots": ["default"], "events": [ "sort", "search", @@ -549,15 +405,7 @@ "demoCount": 3, "propCount": 25, "slots": [], - "events": [ - "input", - "change", - "open", - "close", - "focus", - "blur", - "invalid" - ], + "events": ["input", "change", "open", "close", "focus", "blur", "invalid"], "profiled": false }, { @@ -568,13 +416,8 @@ "purpose": "Theme-aware, responsive device frame component.", "demoCount": 3, "propCount": 14, - "slots": [ - "default" - ], - "events": [ - "change", - "rotate" - ], + "slots": ["default"], + "events": ["change", "rotate"], "profiled": false }, { @@ -597,17 +440,8 @@ "purpose": "Theme-aware, responsive drag and drop component.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "dragStart", - "dragEnd", - "dragEnter", - "dragLeave", - "drop", - "change" - ], + "slots": ["default"], + "events": ["dragStart", "dragEnd", "dragEnter", "dragLeave", "drop", "change"], "profiled": false }, { @@ -618,17 +452,8 @@ "purpose": "Present responsive modal side or bottom content with focus management, backdrop behavior, slots, and close events.", "demoCount": 3, "propCount": 20, - "slots": [ - "trigger", - "header", - "default", - "footer" - ], - "events": [ - "open", - "close", - "cancel" - ], + "slots": ["trigger", "header", "default", "footer"], + "events": ["open", "close", "cancel"], "profiled": true }, { @@ -639,19 +464,8 @@ "purpose": "Open an accessible anchored menu with keyboard navigation, item selection, actions, and responsive placement.", "demoCount": 3, "propCount": 17, - "slots": [ - "trigger", - "header", - "default", - "footer" - ], - "events": [ - "toggle", - "open", - "close", - "select", - "action" - ], + "slots": ["trigger", "header", "default", "footer"], + "events": ["toggle", "open", "close", "select", "action"], "profiled": true }, { @@ -662,12 +476,7 @@ "purpose": "Present one linked feature or service with media, icon, badge, description, and action.", "demoCount": 3, "propCount": 28, - "slots": [ - "media", - "icon", - "default", - "footer" - ], + "slots": ["media", "icon", "default", "footer"], "events": [], "profiled": true }, @@ -679,9 +488,7 @@ "purpose": "Arrange feature cards, services, solutions, or benefits in a responsive equal-height grid.", "demoCount": 3, "propCount": 14, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -693,10 +500,7 @@ "purpose": "Present a compact feature or benefit with a styled icon, title, description, badge, and optional link.", "demoCount": 3, "propCount": 14, - "slots": [ - "default", - "footer" - ], + "slots": ["default", "footer"], "events": [], "profiled": true }, @@ -709,15 +513,7 @@ "demoCount": 3, "propCount": 21, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur", - "select", - "clear", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "select", "clear", "invalid"], "profiled": false }, { @@ -729,11 +525,7 @@ "demoCount": 3, "propCount": 13, "slots": [], - "events": [ - "cancel", - "retry", - "complete" - ], + "events": ["cancel", "retry", "complete"], "profiled": false }, { @@ -744,16 +536,8 @@ "purpose": "Render structured responsive footer navigation, pre and post content, copyright content, links, and public events.", "demoCount": 3, "propCount": 8, - "slots": [ - "pre-footer", - "post-footer", - "copyright-left", - "copyright-right" - ], - "events": [ - "select", - "action" - ], + "slots": ["pre-footer", "post-footer", "copyright-left", "copyright-right"], + "events": ["select", "action"], "profiled": true }, { @@ -764,9 +548,7 @@ "purpose": "Arrange arbitrary content in a responsive configurable CSS grid with stable columns, gaps, alignment, and width.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -778,14 +560,7 @@ "purpose": "Build a full-width responsive hero with constrained content, actions, trust signals, and a structured or custom visual panel.", "demoCount": 3, "propCount": 38, - "slots": [ - "eyebrow", - "actions", - "trust", - "default", - "visual", - "footer" - ], + "slots": ["eyebrow", "actions", "trust", "default", "visual", "footer"], "events": [], "profiled": true }, @@ -797,9 +572,7 @@ "purpose": "Group hero and campaign actions with consistent alignment, orientation, sizing, and responsive mobile stacking.", "demoCount": 3, "propCount": 8, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -811,9 +584,7 @@ "purpose": "Render a responsive image with explicit dimensions, loading behavior, alternative text, sizing, and rounded treatment.", "demoCount": 3, "propCount": 10, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -826,15 +597,7 @@ "demoCount": 3, "propCount": 28, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur", - "invalid", - "keydown", - "keyup" - ], + "events": ["input", "change", "focus", "blur", "invalid", "keydown", "keyup"], "profiled": false }, { @@ -846,14 +609,7 @@ "demoCount": 3, "propCount": 23, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur", - "submit", - "action" - ], + "events": ["input", "change", "focus", "blur", "submit", "action"], "profiled": false }, { @@ -865,12 +621,7 @@ "demoCount": 12, "propCount": 40, "slots": [], - "events": [ - "input", - "change", - "increment", - "decrement" - ], + "events": ["input", "change", "increment", "decrement"], "profiled": false }, { @@ -881,9 +632,7 @@ "purpose": "Theme-aware, responsive kbd component.", "demoCount": 3, "propCount": 4, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": false }, @@ -895,14 +644,8 @@ "purpose": "Theme-aware, responsive layout splitter component.", "demoCount": 2, "propCount": 7, - "slots": [ - "start", - "end", - "default" - ], - "events": [ - "sizeChange" - ], + "slots": ["start", "end", "default"], + "events": ["sizeChange"], "profiled": true }, { @@ -913,13 +656,8 @@ "purpose": "Theme-aware, responsive legend indicator component.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "toggle", - "select" - ], + "slots": ["default"], + "events": ["toggle", "select"], "profiled": false }, { @@ -930,9 +668,7 @@ "purpose": "Render an accessible internal or external link with target, relation, size, color, and public focus or click events.", "demoCount": 3, "propCount": 9, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -944,12 +680,8 @@ "purpose": "Present structured responsive linked or status items with icons, descriptions, actions, and selection events.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "select" - ], + "slots": ["default"], + "events": ["select"], "profiled": true }, { @@ -960,13 +692,8 @@ "purpose": "Theme-aware, responsive list group component.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "select", - "change" - ], + "slots": ["default"], + "events": ["select", "change"], "profiled": false }, { @@ -977,14 +704,8 @@ "purpose": "Present responsive location information and markers with map-ready metadata and movement or marker events.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "markerClick", - "select", - "zoom" - ], + "slots": ["default"], + "events": ["markerClick", "select", "zoom"], "profiled": true }, { @@ -995,11 +716,7 @@ "purpose": "Introduce marketing content with an eyebrow, title, description, and optional linked action.", "demoCount": 3, "propCount": 12, - "slots": [ - "icon", - "actions", - "default" - ], + "slots": ["icon", "actions", "default"], "events": [], "profiled": true }, @@ -1011,13 +728,8 @@ "purpose": "Continuously present responsive labels, partners, notices, or capabilities with pause and resume behavior.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "pause", - "resume" - ], + "slots": ["default"], + "events": ["pause", "resume"], "profiled": true }, { @@ -1028,14 +740,8 @@ "purpose": "Theme-aware, responsive mega menu component.", "demoCount": 2, "propCount": 8, - "slots": [ - "default" - ], - "events": [ - "open", - "close", - "select" - ], + "slots": ["default"], + "events": ["open", "close", "select"], "profiled": true }, { @@ -1046,14 +752,8 @@ "purpose": "Display one operational metric with value, suffix, description, icon, trend, progress, and optional action.", "demoCount": 3, "propCount": 28, - "slots": [ - "default", - "footer" - ], - "events": [ - "select", - "action" - ], + "slots": ["default", "footer"], + "events": ["select", "action"], "profiled": true }, { @@ -1064,13 +764,8 @@ "purpose": "Arrange operational metrics, KPIs, public statistics, or service indicators in a responsive equal-height grid.", "demoCount": 3, "propCount": 13, - "slots": [ - "default" - ], - "events": [ - "select", - "action" - ], + "slots": ["default"], + "events": ["select", "action"], "profiled": true }, { @@ -1081,18 +776,8 @@ "purpose": "Present an accessible modal dialog with focus management, confirmation, cancellation, slots, and responsive sizing.", "demoCount": 3, "propCount": 29, - "slots": [ - "trigger", - "header", - "default", - "footer" - ], - "events": [ - "open", - "close", - "cancel", - "confirm" - ], + "slots": ["trigger", "header", "default", "footer"], + "events": ["open", "close", "cancel", "confirm"], "profiled": true }, { @@ -1103,12 +788,8 @@ "purpose": "Theme-aware, responsive nav component.", "demoCount": 3, "propCount": 9, - "slots": [ - "default" - ], - "events": [ - "select" - ], + "slots": ["default"], + "events": ["select"], "profiled": true }, { @@ -1119,17 +800,8 @@ "purpose": "Theme-aware, responsive navbar component.", "demoCount": 3, "propCount": 13, - "slots": [ - "topbar", - "actions" - ], - "events": [ - "toggle", - "open", - "close", - "select", - "action" - ], + "slots": ["topbar", "actions"], + "events": ["toggle", "open", "close", "select", "action"], "profiled": true }, { @@ -1140,11 +812,7 @@ "purpose": "Introduce an internal or public page with breadcrumbs, icon, title, description, and primary or secondary actions.", "demoCount": 3, "propCount": 25, - "slots": [ - "meta", - "actions", - "default" - ], + "slots": ["meta", "actions", "default"], "events": [], "profiled": true }, @@ -1156,14 +824,8 @@ "purpose": "Theme-aware, responsive pagination component.", "demoCount": 3, "propCount": 12, - "slots": [ - "default" - ], - "events": [ - "change", - "previous", - "next" - ], + "slots": ["default"], + "events": ["change", "previous", "next"], "profiled": true }, { @@ -1175,14 +837,7 @@ "demoCount": 16, "propCount": 26, "slots": [], - "events": [ - "input", - "change", - "complete", - "paste", - "clear", - "error" - ], + "events": ["input", "change", "complete", "paste", "clear", "error"], "profiled": false }, { @@ -1193,18 +848,8 @@ "purpose": "Display anchored supporting content with configurable trigger, placement, responsive sizing, and open or close events.", "demoCount": 3, "propCount": 23, - "slots": [ - "trigger", - "header", - "default", - "footer" - ], - "events": [ - "toggle", - "open", - "close", - "action" - ], + "slots": ["trigger", "header", "default", "footer"], + "events": ["toggle", "open", "close", "action"], "profiled": true }, { @@ -1215,13 +860,8 @@ "purpose": "Reusable portal dashboard component.", "demoCount": 3, "propCount": 14, - "slots": [ - "hero-action" - ], - "events": [ - "action", - "navigate" - ], + "slots": ["hero-action"], + "events": ["action", "navigate"], "profiled": false }, { @@ -1233,11 +873,7 @@ "demoCount": 3, "propCount": 9, "slots": [], - "events": [ - "theme", - "color", - "language" - ], + "events": ["theme", "color", "language"], "profiled": false }, { @@ -1260,11 +896,7 @@ "purpose": "Provide the outer responsive structure, width, background, slots, overflow, and minimum-height behavior for public pages.", "demoCount": 3, "propCount": 10, - "slots": [ - "before", - "default", - "after" - ], + "slots": ["before", "default", "after"], "events": [], "profiled": true }, @@ -1277,13 +909,7 @@ "demoCount": 3, "propCount": 25, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "invalid"], "profiled": false }, { @@ -1295,12 +921,7 @@ "demoCount": 3, "propCount": 26, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur" - ], + "events": ["input", "change", "focus", "blur"], "profiled": false }, { @@ -1311,13 +932,8 @@ "purpose": "Theme-aware, responsive rating component.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "input", - "change" - ], + "slots": ["default"], + "events": ["input", "change"], "profiled": false }, { @@ -1328,12 +944,8 @@ "purpose": "Theme-aware, responsive scrollspy component.", "demoCount": 2, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "change" - ], + "slots": ["default"], + "events": ["change"], "profiled": true }, { @@ -1345,10 +957,7 @@ "demoCount": 3, "propCount": 13, "slots": [], - "events": [ - "search", - "clear" - ], + "events": ["search", "clear"], "profiled": true }, { @@ -1359,9 +968,7 @@ "purpose": "Create a responsive themed page section with controlled spacing, width, borders, and surface treatment.", "demoCount": 3, "propCount": 10, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -1373,11 +980,7 @@ "purpose": "Introduce a section with an eyebrow, title, description, alignment, and responsive heading hierarchy.", "demoCount": 3, "propCount": 10, - "slots": [ - "icon", - "default", - "actions" - ], + "slots": ["icon", "default", "actions"], "events": [], "profiled": true }, @@ -1390,15 +993,7 @@ "demoCount": 3, "propCount": 22, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur", - "open", - "close", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], "profiled": false }, { @@ -1409,16 +1004,8 @@ "purpose": "Theme-aware, responsive sidebar component.", "demoCount": 2, "propCount": 8, - "slots": [ - "default", - "drawer" - ], - "events": [ - "toggle", - "open", - "close", - "select" - ], + "slots": ["default", "drawer"], + "events": ["toggle", "open", "close", "select"], "profiled": true }, { @@ -1453,12 +1040,7 @@ "purpose": "Build a responsive two-column introduction balancing descriptive content with a visual, image, or structured data panel.", "demoCount": 3, "propCount": 31, - "slots": [ - "default", - "actions", - "trust", - "visual" - ], + "slots": ["default", "actions", "trust", "visual"], "events": [], "profiled": true }, @@ -1482,18 +1064,8 @@ "purpose": "Theme-aware, responsive stepper component.", "demoCount": 5, "propCount": 16, - "slots": [ - "step-{index}", - "panel-{index}", - "default" - ], - "events": [ - "change", - "back", - "next", - "skip", - "finish" - ], + "slots": ["step-{index}", "panel-{index}", "default"], + "events": ["change", "back", "next", "skip", "finish"], "profiled": true }, { @@ -1505,11 +1077,7 @@ "demoCount": 6, "propCount": 27, "slots": [], - "events": [ - "input", - "change", - "strength" - ], + "events": ["input", "change", "strength"], "profiled": false }, { @@ -1520,9 +1088,7 @@ "purpose": "Theme-aware, responsive styled icon component.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": false }, @@ -1535,12 +1101,7 @@ "demoCount": 3, "propCount": 20, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur" - ], + "events": ["input", "change", "focus", "blur"], "profiled": false }, { @@ -1551,14 +1112,8 @@ "purpose": "Switch between related responsive content panels with horizontal or vertical orientation and selection events.", "demoCount": 4, "propCount": 9, - "slots": [ - "panel-{valueOf(item, index)}", - "default" - ], - "events": [ - "change", - "select" - ], + "slots": ["panel-{valueOf(item, index)}", "default"], + "events": ["change", "select"], "profiled": true }, { @@ -1570,11 +1125,7 @@ "demoCount": 3, "propCount": 14, "slots": [], - "events": [ - "click", - "focus", - "blur" - ], + "events": ["click", "focus", "blur"], "profiled": true }, { @@ -1586,13 +1137,7 @@ "demoCount": 3, "propCount": 23, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "invalid"], "profiled": false }, { @@ -1604,15 +1149,7 @@ "demoCount": 3, "propCount": 26, "slots": [], - "events": [ - "input", - "change", - "focus", - "blur", - "open", - "close", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], "profiled": false }, { @@ -1623,12 +1160,8 @@ "purpose": "Present responsive chronological activity, milestones, or workflow status with rich item metadata.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "select" - ], + "slots": ["default"], + "events": ["select"], "profiled": true }, { @@ -1640,11 +1173,7 @@ "demoCount": 1, "propCount": 15, "slots": [], - "events": [ - "show", - "dismiss", - "action" - ], + "events": ["show", "dismiss", "action"], "profiled": true }, { @@ -1656,10 +1185,7 @@ "demoCount": 3, "propCount": 23, "slots": [], - "events": [ - "change", - "toggle" - ], + "events": ["change", "toggle"], "profiled": false }, { @@ -1671,11 +1197,7 @@ "demoCount": 10, "propCount": 24, "slots": [], - "events": [ - "input", - "change", - "toggle" - ], + "events": ["input", "change", "toggle"], "profiled": false }, { @@ -1686,15 +1208,8 @@ "purpose": "Show concise accessible contextual help on hover, focus, click, or controlled open state.", "demoCount": 3, "propCount": 17, - "slots": [ - "trigger", - "default" - ], - "events": [ - "toggle", - "open", - "close" - ], + "slots": ["trigger", "default"], + "events": ["toggle", "open", "close"], "profiled": true }, { @@ -1705,15 +1220,8 @@ "purpose": "Theme-aware, responsive tree view component.", "demoCount": 3, "propCount": 10, - "slots": [ - "default" - ], - "events": [ - "select", - "toggle", - "expand", - "collapse" - ], + "slots": ["default"], + "events": ["select", "toggle", "expand", "collapse"], "profiled": false }, { @@ -1724,9 +1232,7 @@ "purpose": "Apply consistent readable responsive typography, widths, columns, spacing, and editorial hierarchy.", "demoCount": 3, "propCount": 6, - "slots": [ - "default" - ], + "slots": ["default"], "events": [], "profiled": true }, @@ -1738,15 +1244,8 @@ "purpose": "Theme-aware, responsive wysiwyg editor component.", "demoCount": 3, "propCount": 7, - "slots": [ - "default" - ], - "events": [ - "input", - "change", - "focus", - "blur" - ], + "slots": ["default"], + "events": ["input", "change", "focus", "blur"], "profiled": false } ] diff --git a/package.json b/package.json index 2bb01659..e2244d64 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "workspaces": [ "packages/*", "examples/*", + "examples/inter-app-api-showcase/apps/*", + "examples/inter-app-api-showcase/packages/*", "services/*" ], "scripts": { diff --git a/packages/compiler/src/client-codegen.ts b/packages/compiler/src/client-codegen.ts index a838719b..7292ba27 100644 --- a/packages/compiler/src/client-codegen.ts +++ b/packages/compiler/src/client-codegen.ts @@ -174,7 +174,7 @@ export function browserModuleRequired(ast: PageAst): boolean { return functions.length > 0 || selectedBrowserImports(ast, functions).length > 0; } -function functionEntry( +function _functionEntry( ast: PageAst, fn: RuntimeFunctionDecl, availableFunctions: string[], @@ -242,7 +242,10 @@ function functionEntry( .join(" "); const peerAliases = !stateNames.length ? 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") : `const __wrnexusFlush = () => { ${syncStateToContext} }; const __wrnexusRestore = () => { ${syncStateFromContext} }; @@ -271,9 +274,15 @@ function functionEntry( 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(() => { + ${ + !parameterNames.has("setTimeout") && + !declaredLocals.has("setTimeout") && + !functionAliases.includes("setTimeout") + ? `const setTimeout = (callback, delay, ...args) => globalThis.setTimeout(() => { try { return callback(...args); } finally { __wrnexusCommit(); } - }, delay);` : ""}` + }, delay);` + : "" + }` : ""; const body = eraseFunctionTypes(fn.body); const runtimeBindings = [ @@ -312,10 +321,7 @@ export function generateBrowserModule(ast: PageAst): string { const sharedProps = ast.props .map((entry) => entry.name) .filter( - (name) => - safeIdentifier(name) && - !RUNTIME_BINDINGS.has(name) && - !sharedState.includes(name), + (name) => safeIdentifier(name) && !RUNTIME_BINDINGS.has(name) && !sharedState.includes(name), ); const callableAliases = functionNames.filter( (name) => @@ -362,9 +368,13 @@ function __wrnexusCreateClientFunctions(context) { const __wrnexusCommit = () => { ${sharedCommit} }; const __wrnexusRestore = () => { ${sharedRestore} }; ${!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(); } - }, delay);` : ""} + }, delay);` + : "" + } const implementations = { ${implementations} }; diff --git a/packages/compiler/src/codegen.ts b/packages/compiler/src/codegen.ts index e6d8e28f..fc58c974 100644 --- a/packages/compiler/src/codegen.ts +++ b/packages/compiler/src/codegen.ts @@ -752,8 +752,7 @@ function renderNestedComponentInvocation( if ( !attr.value.includes("{") || - (!exprRefsState(attr.value, ctx.stateNames) && - !exprRefsState(attr.value, ctx.propNames)) + (!exprRefsState(attr.value, ctx.stateNames) && !exprRefsState(attr.value, ctx.propNames)) ) { return rendered; } diff --git a/packages/compiler/test/compiler.test.ts b/packages/compiler/test/compiler.test.ts index 43bec4e1..53b92db2 100644 --- a/packages/compiler/test/compiler.test.ts +++ b/packages/compiler/test/compiler.test.ts @@ -328,9 +328,7 @@ test("stateful component keeps both prop and state text reactive", async () => { const out = render({ start: "10", label: "Score" }); expect(out).toContain('data-scope="start: 10, label: "Score", count: 10"'); expect(out).toContain('data-on-click="count++"'); - expect(out).toContain( - 'Score: 10', - ); + expect(out).toContain('Score: 10'); expect(out).toContain('data-scope="'); diff --git a/packages/csr/src/index.ts b/packages/csr/src/index.ts index 34a4341a..2d494a89 100644 --- a/packages/csr/src/index.ts +++ b/packages/csr/src/index.ts @@ -89,7 +89,10 @@ const CONTROLLER_LOADER = String.raw` /** The reactive runtime served at `/__wrnexus/reactive.js` (plain browser JS). */ export function getReactiveRuntime(development = false): string { 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( " hydrateNavbarControllers(host);\n hydratePreferenceControllers(host);\n hydrateSelectControllers(host);\n hydratePinInputControllers(host);", " loadComponentControllers(host);", diff --git a/packages/csr/test/reactive.test.ts b/packages/csr/test/reactive.test.ts index 9a2d089a..260af81c 100644 --- a/packages/csr/test/reactive.test.ts +++ b/packages/csr/test/reactive.test.ts @@ -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", () => { - const win = mount(`
{count}
`, getReactiveRuntime(true)); + const win = mount( + `
{count}
`, + getReactiveRuntime(true), + ); 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", () => { const win = new Window() as unknown as Window & Record; - win.document.body.innerHTML = - `
`; + win.document.body.innerHTML = `
`; (globalThis as Record).window = win; (globalThis as Record).document = win.document; (globalThis as Record).location = win.location; - (globalThis as Record).NodeFilter = (win as unknown as { NodeFilter: unknown }).NodeFilter; - (globalThis as Record).MutationObserver = (win as unknown as { MutationObserver: unknown }).MutationObserver; - (globalThis as Record).CustomEvent = (win as unknown as { CustomEvent: unknown }).CustomEvent; + (globalThis as Record).NodeFilter = ( + win as unknown as { NodeFilter: unknown } + ).NodeFilter; + (globalThis as Record).MutationObserver = ( + win as unknown as { MutationObserver: unknown } + ).MutationObserver; + (globalThis as Record).CustomEvent = ( + win as unknown as { CustomEvent: unknown } + ).CustomEvent; const warnings: unknown[][] = []; const originalWarn = console.warn; console.warn = (...args: unknown[]) => warnings.push(args); try { (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(); } finally { @@ -730,15 +740,21 @@ test("development runtime warns when a component binding names a missing functio const win = new Window() as unknown as Window & Record; win.document.body.innerHTML = `
` + - `
` + - `
` + - `
`; + `
` + + `
` + + `
`; (globalThis as Record).window = win; (globalThis as Record).document = win.document; (globalThis as Record).location = win.location; - (globalThis as Record).NodeFilter = (win as unknown as { NodeFilter: unknown }).NodeFilter; - (globalThis as Record).MutationObserver = (win as unknown as { MutationObserver: unknown }).MutationObserver; - (globalThis as Record).CustomEvent = (win as unknown as { CustomEvent: unknown }).CustomEvent; + (globalThis as Record).NodeFilter = ( + win as unknown as { NodeFilter: unknown } + ).NodeFilter; + (globalThis as Record).MutationObserver = ( + win as unknown as { MutationObserver: unknown } + ).MutationObserver; + (globalThis as Record).CustomEvent = ( + win as unknown as { CustomEvent: unknown } + ).CustomEvent; const warnings: unknown[][] = []; const originalWarn = console.warn; const originalError = console.error; @@ -746,7 +762,9 @@ test("development runtime warns when a component binding names a missing functio console.error = () => {}; try { (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 { __wrnexusOutputHandlers?: Record unknown>>; }; @@ -770,15 +788,23 @@ test("development runtime warns for referenced theme tokens absent from rendered (globalThis as Record).window = win; (globalThis as Record).document = win.document; (globalThis as Record).location = win.location; - (globalThis as Record).NodeFilter = (win as unknown as { NodeFilter: unknown }).NodeFilter; - (globalThis as Record).MutationObserver = (win as unknown as { MutationObserver: unknown }).MutationObserver; - (globalThis as Record).CustomEvent = (win as unknown as { CustomEvent: unknown }).CustomEvent; + (globalThis as Record).NodeFilter = ( + win as unknown as { NodeFilter: unknown } + ).NodeFilter; + (globalThis as Record).MutationObserver = ( + win as unknown as { MutationObserver: unknown } + ).MutationObserver; + (globalThis as Record).CustomEvent = ( + win as unknown as { CustomEvent: unknown } + ).CustomEvent; const warnings: unknown[][] = []; const originalWarn = console.warn; console.warn = (...args: unknown[]) => warnings.push(args); try { (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 { console.warn = originalWarn; } diff --git a/packages/dev-server/test/component-composition-runtime.test.ts b/packages/dev-server/test/component-composition-runtime.test.ts index bd53ce5d..ea185c10 100644 --- a/packages/dev-server/test/component-composition-runtime.test.ts +++ b/packages/dev-server/test/component-composition-runtime.test.ts @@ -31,7 +31,8 @@ test("a component nested in another component's slot keeps its boundary", async return { render: (props: Record) => `${props.label}` }; } return { - default: () => '
', + default: () => + '
', }; }, getMiddleware: async () => [], diff --git a/packages/ui/component-catalog.json b/packages/ui/component-catalog.json index 34921242..ab49f7c3 100644 --- a/packages/ui/component-catalog.json +++ b/packages/ui/component-catalog.json @@ -1,7 +1,5 @@ { - "sourceDocuments": [ - "Screenshot-directed WRNexus UI catalog reset" - ], + "sourceDocuments": ["Screenshot-directed WRNexus UI catalog reset"], "components": [ { "name": "Accordion", diff --git a/packages/ui/component-reference.json b/packages/ui/component-reference.json index 7a569166..9fa6cdf1 100644 --- a/packages/ui/component-reference.json +++ b/packages/ui/component-reference.json @@ -143,11 +143,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "change", - "open", - "close" - ], + "events": ["change", "open", "close"], "source": "components/Accordion.wrn" }, { @@ -549,16 +545,7 @@ "payloadType": "{ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string" } ], - "events": [ - "search", - "select", - "change", - "clear", - "open", - "close", - "load", - "error" - ], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], "source": "components/AdvancedSelect.wrn" }, { @@ -726,10 +713,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "dismiss", - "action" - ], + "events": ["dismiss", "action"], "source": "components/alert.wrn" }, { @@ -879,9 +863,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "dismiss" - ], + "events": ["dismiss"], "source": "components/AnnouncementBar.wrn" }, { @@ -982,9 +964,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "submit", @@ -1007,13 +987,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "submit", - "change", - "input", - "focus", - "blur" - ], + "events": ["submit", "change", "input", "focus", "blur"], "source": "components/AuthForm.wrn" }, { @@ -1079,10 +1053,7 @@ "options": [] } ], - "slots": [ - "aside-extra", - "form" - ], + "slots": ["aside-extra", "form"], "outputs": [], "events": [], "source": "components/AuthSplitLayout.wrn" @@ -1235,11 +1206,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "load", - "error", - "click" - ], + "events": ["load", "error", "click"], "source": "components/avatar.wrn" }, { @@ -1340,9 +1307,7 @@ "payloadType": "{ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]" } ], - "events": [ - "overflow" - ], + "events": ["overflow"], "source": "components/AvatarGroup.wrn" }, { @@ -1630,9 +1595,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "dismiss" - ], + "events": ["dismiss"], "source": "components/badge.wrn" }, { @@ -1733,9 +1696,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/Blockquote.wrn" @@ -1838,9 +1799,7 @@ "payloadType": "{ value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null" } ], - "events": [ - "select" - ], + "events": ["select"], "source": "components/Breadcrumb.wrn" }, { @@ -2025,9 +1984,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "click", @@ -2042,11 +1999,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "click", - "focus", - "blur" - ], + "events": ["click", "focus", "blur"], "source": "components/button.wrn" }, { @@ -2147,9 +2100,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "click", @@ -2164,11 +2115,7 @@ "payloadType": "{ value: string | number | boolean | null | object; previousValue: string | number | boolean | null | object; item: string | number | boolean | null | object; index: number }" } ], - "events": [ - "click", - "select", - "change" - ], + "events": ["click", "select", "change"], "source": "components/ButtonGroup.wrn" }, { @@ -2353,12 +2300,7 @@ "options": [] } ], - "slots": [ - "default", - "actions", - "visual", - "footer" - ], + "slots": ["default", "actions", "visual", "footer"], "outputs": [], "events": [], "source": "components/CTASection.wrn" @@ -2587,9 +2529,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "click", @@ -2616,14 +2556,7 @@ "payloadType": "{ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string" } ], - "events": [ - "click", - "action", - "navigate", - "dismiss", - "load", - "error" - ], + "events": ["click", "action", "navigate", "dismiss", "load", "error"], "source": "components/Card.wrn" }, { @@ -2787,9 +2720,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "initialize", @@ -2937,9 +2868,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "select", @@ -2954,11 +2883,7 @@ "payloadType": "{ item: object; index: number; hidden: boolean; sourceEvent?: Event }" } ], - "events": [ - "select", - "dataPointClick", - "legendToggle" - ], + "events": ["select", "dataPointClick", "legendToggle"], "source": "components/Chart.wrn" }, { @@ -3045,9 +2970,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "action", @@ -3066,12 +2989,7 @@ "payloadType": "{ link: string | number | boolean | null | object; item: string | number | boolean | null | object; index: number }" } ], - "events": [ - "action", - "messageClick", - "avatarClick", - "linkClick" - ], + "events": ["action", "messageClick", "avatarClick", "linkClick"], "source": "components/ChatBubble.wrn" }, { @@ -3270,9 +3188,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "input", @@ -3295,13 +3211,7 @@ "payloadType": "{ message?: string; value: string | number | boolean | null | object; sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "input", - "change", - "focus", - "blur", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "invalid"], "source": "components/checkbox.wrn" }, { @@ -3388,9 +3298,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "copy", @@ -3405,11 +3313,7 @@ "payloadType": "{ error: Error | string; value: string; sourceEvent?: Event }" } ], - "events": [ - "copy", - "success", - "error" - ], + "events": ["copy", "success", "error"], "source": "components/Clipboard.wrn" }, { @@ -3475,9 +3379,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "toggle", @@ -3492,11 +3394,7 @@ "payloadType": "{ index: number; item: string | number | boolean | null | object }" } ], - "events": [ - "toggle", - "open", - "close" - ], + "events": ["toggle", "open", "close"], "source": "components/Collapse.wrn" }, { @@ -3658,12 +3556,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "input", - "change", - "focus", - "blur" - ], + "events": ["input", "change", "focus", "blur"], "source": "components/ColorPicker.wrn" }, { @@ -3715,9 +3608,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/Columns.wrn" @@ -4051,16 +3942,7 @@ "payloadType": "{ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string" } ], - "events": [ - "search", - "select", - "change", - "clear", - "open", - "close", - "load", - "error" - ], + "events": ["search", "select", "change", "clear", "open", "close", "load", "error"], "source": "components/Combobox.wrn" }, { @@ -4126,9 +4008,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "start", @@ -4139,10 +4019,7 @@ "payloadType": "{ sourceEvent?: Event; duration: number }" } ], - "events": [ - "start", - "complete" - ], + "events": ["start", "complete"], "source": "components/Confetti.wrn" }, { @@ -4201,9 +4078,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/Container.wrn" @@ -4341,12 +4216,7 @@ "options": [] } ], - "slots": [ - "trigger", - "header", - "default", - "footer" - ], + "slots": ["trigger", "header", "default", "footer"], "outputs": [ { "name": "open", @@ -4365,12 +4235,7 @@ "payloadType": "{ item: string | number | boolean | null | object; itemIndex: number; value: string | number | boolean; sourceEvent: Event }" } ], - "events": [ - "open", - "close", - "select", - "action" - ], + "events": ["open", "close", "select", "action"], "source": "components/ContextMenu.wrn" }, { @@ -4429,9 +4294,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/CustomScrollbar.wrn" @@ -4492,9 +4355,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "select", @@ -4505,10 +4366,7 @@ "payloadType": "{ value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null" } ], - "events": [ - "select", - "change" - ], + "events": ["select", "change"], "source": "components/DataMap.wrn" }, { @@ -4721,9 +4579,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "sort", @@ -4983,15 +4839,7 @@ "payloadType": "{ name: string; message: string; sourceEvent: Event }" } ], - "events": [ - "input", - "change", - "open", - "close", - "focus", - "blur", - "invalid" - ], + "events": ["input", "change", "open", "close", "focus", "blur", "invalid"], "source": "components/DatePicker.wrn" }, { @@ -5099,9 +4947,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "change", @@ -5112,10 +4958,7 @@ "payloadType": "{ device: string; orientation: string; sourceEvent: Event }" } ], - "events": [ - "change", - "rotate" - ], + "events": ["change", "rotate"], "source": "components/DeviceFrame.wrn" }, { @@ -5228,9 +5071,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "dragStart", @@ -5257,14 +5098,7 @@ "payloadType": "{ value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null" } ], - "events": [ - "dragStart", - "dragEnd", - "dragEnter", - "dragLeave", - "drop", - "change" - ], + "events": ["dragStart", "dragEnd", "dragEnter", "dragLeave", "drop", "change"], "source": "components/DragAndDrop.wrn" }, { @@ -5414,12 +5248,7 @@ "options": [] } ], - "slots": [ - "trigger", - "header", - "default", - "footer" - ], + "slots": ["trigger", "header", "default", "footer"], "outputs": [ { "name": "open", @@ -5434,11 +5263,7 @@ "payloadType": "{ placement: string; sourceEvent: Event }" } ], - "events": [ - "open", - "close", - "cancel" - ], + "events": ["open", "close", "cancel"], "source": "components/Drawer.wrn" }, { @@ -5567,12 +5392,7 @@ "options": [] } ], - "slots": [ - "trigger", - "header", - "default", - "footer" - ], + "slots": ["trigger", "header", "default", "footer"], "outputs": [ { "name": "toggle", @@ -5595,13 +5415,7 @@ "payloadType": "{ item: string | number | boolean | null | object; itemIndex: number; value: string | number | boolean; sourceEvent: Event }" } ], - "events": [ - "toggle", - "open", - "close", - "select", - "action" - ], + "events": ["toggle", "open", "close", "select", "action"], "source": "components/Dropdown.wrn" }, { @@ -5807,12 +5621,7 @@ "options": [] } ], - "slots": [ - "media", - "icon", - "default", - "footer" - ], + "slots": ["media", "icon", "default", "footer"], "outputs": [], "events": [], "source": "components/FeatureCard.wrn" @@ -5922,9 +5731,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/FeatureGrid.wrn" @@ -6034,10 +5841,7 @@ "options": [] } ], - "slots": [ - "default", - "footer" - ], + "slots": ["default", "footer"], "outputs": [], "events": [], "source": "components/FeatureIconCard.wrn" @@ -6227,15 +6031,7 @@ "payloadType": "{ message?: string; value: string | number | boolean | null | object; sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "input", - "change", - "focus", - "blur", - "select", - "clear", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "select", "clear", "invalid"], "source": "components/FileInput.wrn" }, { @@ -6351,11 +6147,7 @@ "payloadType": "{ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]" } ], - "events": [ - "cancel", - "retry", - "complete" - ], + "events": ["cancel", "retry", "complete"], "source": "components/FileUploadProgress.wrn" }, { @@ -6421,12 +6213,7 @@ "options": [] } ], - "slots": [ - "pre-footer", - "post-footer", - "copyright-left", - "copyright-right" - ], + "slots": ["pre-footer", "post-footer", "copyright-left", "copyright-right"], "outputs": [ { "name": "select", @@ -6437,10 +6224,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "select", - "action" - ], + "events": ["select", "action"], "source": "components/Footer.wrn" }, { @@ -6499,9 +6283,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/Grid.wrn" @@ -6779,14 +6561,7 @@ "options": [] } ], - "slots": [ - "eyebrow", - "actions", - "trust", - "default", - "visual", - "footer" - ], + "slots": ["eyebrow", "actions", "trust", "default", "visual", "footer"], "outputs": [], "events": [], "source": "components/Hero.wrn" @@ -6854,9 +6629,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/HeroActions.wrn" @@ -6938,9 +6711,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/Image.wrn" @@ -7179,15 +6950,7 @@ "payloadType": "{ key: string; value: string | number | boolean | null | object; name: string; sourceEvent: Event }" } ], - "events": [ - "input", - "change", - "focus", - "blur", - "invalid", - "keydown", - "keyup" - ], + "events": ["input", "change", "focus", "blur", "invalid", "keydown", "keyup"], "source": "components/input.wrn" }, { @@ -7385,14 +7148,7 @@ "payloadType": "{ name: string; sourceEvent: Event }" } ], - "events": [ - "input", - "change", - "focus", - "blur", - "submit", - "action" - ], + "events": ["input", "change", "focus", "blur", "submit", "action"], "source": "components/InputGroup.wrn" }, { @@ -7701,12 +7457,7 @@ "payloadType": "{ value: number; previousValue?: number; sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "input", - "change", - "increment", - "decrement" - ], + "events": ["input", "change", "increment", "decrement"], "source": "components/InputNumber.wrn" }, { @@ -7744,9 +7495,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/Kbd.wrn" @@ -7807,20 +7556,14 @@ "options": [] } ], - "slots": [ - "start", - "end", - "default" - ], + "slots": ["start", "end", "default"], "outputs": [ { "name": "sizeChange", "payloadType": "{ size: number }" } ], - "events": [ - "sizeChange" - ], + "events": ["sizeChange"], "source": "components/LayoutSplitter.wrn" }, { @@ -7879,9 +7622,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "toggle", @@ -7892,10 +7633,7 @@ "payloadType": "{ value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null" } ], - "events": [ - "toggle", - "select" - ], + "events": ["toggle", "select"], "source": "components/LegendIndicator.wrn" }, { @@ -7968,9 +7706,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/Link.wrn" @@ -8031,18 +7767,14 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "select", "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "select" - ], + "events": ["select"], "source": "components/List.wrn" }, { @@ -8101,9 +7833,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "select", @@ -8114,10 +7844,7 @@ "payloadType": "{ value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null" } ], - "events": [ - "select", - "change" - ], + "events": ["select", "change"], "source": "components/ListGroup.wrn" }, { @@ -8176,9 +7903,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "markerClick", @@ -8193,11 +7918,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "markerClick", - "select", - "zoom" - ], + "events": ["markerClick", "select", "zoom"], "source": "components/Map.wrn" }, { @@ -8291,11 +8012,7 @@ "options": [] } ], - "slots": [ - "icon", - "actions", - "default" - ], + "slots": ["icon", "actions", "default"], "outputs": [], "events": [], "source": "components/MarketingSectionHeader.wrn" @@ -8356,9 +8073,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "pause", @@ -8369,10 +8084,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "pause", - "resume" - ], + "events": ["pause", "resume"], "source": "components/Marquee.wrn" }, { @@ -8438,9 +8150,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "open", @@ -8455,11 +8165,7 @@ "payloadType": "{ item: object; value: string }" } ], - "events": [ - "open", - "close", - "select" - ], + "events": ["open", "close", "select"], "source": "components/MegaMenu.wrn" }, { @@ -8665,10 +8371,7 @@ "options": [] } ], - "slots": [ - "default", - "footer" - ], + "slots": ["default", "footer"], "outputs": [ { "name": "select", @@ -8679,10 +8382,7 @@ "payloadType": "{ label: string; value: string; href: string; sourceEvent: Event }" } ], - "events": [ - "select", - "action" - ], + "events": ["select", "action"], "source": "components/MetricCard.wrn" }, { @@ -8783,9 +8483,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "select", @@ -8796,10 +8494,7 @@ "payloadType": "{ item: string | number | boolean | null | object; itemIndex: number; sourceEvent: Event }" } ], - "events": [ - "select", - "action" - ], + "events": ["select", "action"], "source": "components/MetricGrid.wrn" }, { @@ -9012,12 +8707,7 @@ "options": [] } ], - "slots": [ - "trigger", - "header", - "default", - "footer" - ], + "slots": ["trigger", "header", "default", "footer"], "outputs": [ { "name": "open", @@ -9036,12 +8726,7 @@ "payloadType": "{ sourceEvent: Event }" } ], - "events": [ - "open", - "close", - "cancel", - "confirm" - ], + "events": ["open", "close", "cancel", "confirm"], "source": "components/Modal.wrn" }, { @@ -9114,18 +8799,14 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "select", "payloadType": "{ item: object; value: string }" } ], - "events": [ - "select" - ], + "events": ["select"], "source": "components/Nav.wrn" }, { @@ -9226,10 +8907,7 @@ "options": [] } ], - "slots": [ - "topbar", - "actions" - ], + "slots": ["topbar", "actions"], "outputs": [ { "name": "toggle", @@ -9252,13 +8930,7 @@ "payloadType": "{ item: string | number | boolean | null | object; value: string | number | boolean }" } ], - "events": [ - "toggle", - "open", - "close", - "select", - "action" - ], + "events": ["toggle", "open", "close", "select", "action"], "source": "components/Navbar.wrn" }, { @@ -9443,11 +9115,7 @@ "options": [] } ], - "slots": [ - "meta", - "actions", - "default" - ], + "slots": ["meta", "actions", "default"], "outputs": [], "events": [], "source": "components/PageHeader.wrn" @@ -9543,9 +9211,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "change", @@ -9560,11 +9226,7 @@ "payloadType": "{ page: number }" } ], - "events": [ - "change", - "previous", - "next" - ], + "events": ["change", "previous", "next"], "source": "components/Pagination.wrn" }, { @@ -9783,14 +9445,7 @@ "payloadType": "{ error: Error | string; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | Error | string" } ], - "events": [ - "input", - "change", - "complete", - "paste", - "clear", - "error" - ], + "events": ["input", "change", "complete", "paste", "clear", "error"], "source": "components/PinInput.wrn" }, { @@ -9961,12 +9616,7 @@ "options": [] } ], - "slots": [ - "trigger", - "header", - "default", - "footer" - ], + "slots": ["trigger", "header", "default", "footer"], "outputs": [ { "name": "toggle", @@ -9985,12 +9635,7 @@ "payloadType": "{ href: string; sourceEvent: Event }" } ], - "events": [ - "toggle", - "open", - "close", - "action" - ], + "events": ["toggle", "open", "close", "action"], "source": "components/Popover.wrn" }, { @@ -10098,9 +9743,7 @@ "options": [] } ], - "slots": [ - "hero-action" - ], + "slots": ["hero-action"], "outputs": [ { "name": "action", @@ -10111,10 +9754,7 @@ "payloadType": "{ item: string | number | boolean | null | object; value: string | number | boolean; index: number }" } ], - "events": [ - "action", - "navigate" - ], + "events": ["action", "navigate"], "source": "components/PortalDashboard.wrn" }, { @@ -10202,11 +9842,7 @@ "payloadType": "{ sourceEvent?: Event; value: string | number | boolean | null | object; [key: string]: string | number | boolean | null | object } | string | number | boolean | null | object[]" } ], - "events": [ - "theme", - "color", - "language" - ], + "events": ["theme", "color", "language"], "source": "components/PreferenceSwitcher.wrn" }, { @@ -10347,11 +9983,7 @@ "options": [] } ], - "slots": [ - "before", - "default", - "after" - ], + "slots": ["before", "default", "after"], "outputs": [], "events": [], "source": "components/PublicPageShell.wrn" @@ -10561,13 +10193,7 @@ "payloadType": "{ message?: string; value: string | number | boolean | null | object; sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "input", - "change", - "focus", - "blur", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "invalid"], "source": "components/radio.wrn" }, { @@ -10778,12 +10404,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "input", - "change", - "focus", - "blur" - ], + "events": ["input", "change", "focus", "blur"], "source": "components/RangeSlider.wrn" }, { @@ -10842,9 +10463,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "input", @@ -10855,10 +10474,7 @@ "payloadType": "{ value?: string | number | boolean | null; values?: Array; sourceEvent?: Event; [key: string]: string | number | boolean | null | object } | string | number | boolean | null" } ], - "events": [ - "input", - "change" - ], + "events": ["input", "change"], "source": "components/Rating.wrn" }, { @@ -10917,18 +10533,14 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "change", "payloadType": "{ href: string; label: string }" } ], - "events": [ - "change" - ], + "events": ["change"], "source": "components/Scrollspy.wrn" }, { @@ -11040,10 +10652,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "search", - "clear" - ], + "events": ["search", "clear"], "source": "components/SearchBox.wrn" }, { @@ -11123,9 +10732,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/Section.wrn" @@ -11207,11 +10814,7 @@ "options": [] } ], - "slots": [ - "icon", - "default", - "actions" - ], + "slots": ["icon", "default", "actions"], "outputs": [], "events": [], "source": "components/SectionHeader.wrn" @@ -11408,15 +11011,7 @@ "payloadType": "{ name: string; message: string; sourceEvent: Event }" } ], - "events": [ - "input", - "change", - "focus", - "blur", - "open", - "close", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], "source": "components/select.wrn" }, { @@ -11482,10 +11077,7 @@ "options": [] } ], - "slots": [ - "default", - "drawer" - ], + "slots": ["default", "drawer"], "outputs": [ { "name": "toggle", @@ -11504,12 +11096,7 @@ "payloadType": "{ item: object; value: string; level: number }" } ], - "events": [ - "toggle", - "open", - "close", - "select" - ], + "events": ["toggle", "open", "close", "select"], "source": "components/Sidebar.wrn" }, { @@ -11830,12 +11417,7 @@ "options": [] } ], - "slots": [ - "default", - "actions", - "trust", - "visual" - ], + "slots": ["default", "actions", "trust", "visual"], "outputs": [], "events": [], "source": "components/SplitHero.wrn" @@ -12041,11 +11623,7 @@ "options": [] } ], - "slots": [ - "step-{index}", - "panel-{index}", - "default" - ], + "slots": ["step-{index}", "panel-{index}", "default"], "outputs": [ { "name": "change", @@ -12068,13 +11646,7 @@ "payloadType": "{ index: number; step: object }" } ], - "events": [ - "change", - "back", - "next", - "skip", - "finish" - ], + "events": ["change", "back", "next", "skip", "finish"], "source": "components/Stepper.wrn" }, { @@ -12288,11 +11860,7 @@ "payloadType": "{ value: string; score: number; maximumScore: number; percent: number; level: string }" } ], - "events": [ - "input", - "change", - "strength" - ], + "events": ["input", "change", "strength"], "source": "components/StrongPassword.wrn" }, { @@ -12351,9 +11919,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/StyledIcon.wrn" @@ -12524,12 +12090,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "input", - "change", - "focus", - "blur" - ], + "events": ["input", "change", "focus", "blur"], "source": "components/switch.wrn" }, { @@ -12602,10 +12163,7 @@ "options": [] } ], - "slots": [ - "panel-{valueOf(item, index)}", - "default" - ], + "slots": ["panel-{valueOf(item, index)}", "default"], "outputs": [ { "name": "change", @@ -12616,10 +12174,7 @@ "payloadType": "{ value: string; item: object; index: number }" } ], - "events": [ - "change", - "select" - ], + "events": ["change", "select"], "source": "components/Tabs.wrn" }, { @@ -12742,11 +12297,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "click", - "focus", - "blur" - ], + "events": ["click", "focus", "blur"], "source": "components/TextLink.wrn" }, { @@ -12940,13 +12491,7 @@ "payloadType": "{ value: string | number | boolean | null | object; name: string; message: string; sourceEvent: Event }" } ], - "events": [ - "input", - "change", - "focus", - "blur", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "invalid"], "source": "components/textarea.wrn" }, { @@ -13169,15 +12714,7 @@ "payloadType": "{ name: string; message: string; sourceEvent: Event }" } ], - "events": [ - "input", - "change", - "focus", - "blur", - "open", - "close", - "invalid" - ], + "events": ["input", "change", "focus", "blur", "open", "close", "invalid"], "source": "components/TimePicker.wrn" }, { @@ -13236,18 +12773,14 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "select", "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "select" - ], + "events": ["select"], "source": "components/Timeline.wrn" }, { @@ -13377,11 +12910,7 @@ "payloadType": "{ id: number; sourceEvent: Event }" } ], - "events": [ - "show", - "dismiss", - "action" - ], + "events": ["show", "dismiss", "action"], "source": "components/Toaster.wrn" }, { @@ -13563,10 +13092,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "change", - "toggle" - ], + "events": ["change", "toggle"], "source": "components/ToggleCount.wrn" }, { @@ -13759,11 +13285,7 @@ "payloadType": "{ visible: boolean }" } ], - "events": [ - "input", - "change", - "toggle" - ], + "events": ["input", "change", "toggle"], "source": "components/TogglePassword.wrn" }, { @@ -13892,10 +13414,7 @@ "options": [] } ], - "slots": [ - "trigger", - "default" - ], + "slots": ["trigger", "default"], "outputs": [ { "name": "toggle", @@ -13910,11 +13429,7 @@ "payloadType": "{ reason: string; sourceEvent: Event }" } ], - "events": [ - "toggle", - "open", - "close" - ], + "events": ["toggle", "open", "close"], "source": "components/tooltip.wrn" }, { @@ -13994,9 +13509,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "select", @@ -14015,12 +13528,7 @@ "payloadType": "{ item: object; value: string; sourceEvent?: Event }" } ], - "events": [ - "select", - "toggle", - "expand", - "collapse" - ], + "events": ["select", "toggle", "expand", "collapse"], "source": "components/TreeView.wrn" }, { @@ -14072,9 +13580,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [], "events": [], "source": "components/Typography.wrn" @@ -14135,9 +13641,7 @@ "options": [] } ], - "slots": [ - "default" - ], + "slots": ["default"], "outputs": [ { "name": "input", @@ -14156,12 +13660,7 @@ "payloadType": "{ sourceEvent?: Event; [key: string]: string | number | boolean | null | object }" } ], - "events": [ - "input", - "change", - "focus", - "blur" - ], + "events": ["input", "change", "focus", "blur"], "source": "components/WysiwygEditor.wrn" } ] diff --git a/packages/ui/components/DataTable.wrn b/packages/ui/components/DataTable.wrn index 77c3d270..30e4536c 100644 --- a/packages/ui/components/DataTable.wrn +++ b/packages/ui/components/DataTable.wrn @@ -121,7 +121,7 @@ component DataTable { state query = "" state sortKey = "" state sortDirection = "asc" - state page = 1 + state paginationPage = 1 state perPage = pageSize state selectedKeys = [] state remoteRows = [] @@ -273,7 +273,7 @@ component DataTable { // page number past the end, and a table showing nothing with rows // available is worse than one that quietly lands on the last page. 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() { @@ -576,7 +576,7 @@ component DataTable { sortKey = key sortDirection = "asc" } - page = 1 + paginationPage = 1 output.sort({ key: sortKey, direction: sortDirection }) reload() output.change(viewState()) @@ -584,7 +584,7 @@ component DataTable { client function updateQuery(sourceEvent) { query = sourceEvent.target.value - page = 1 + paginationPage = 1 output.search({ query: query }) reload() output.change(viewState()) @@ -592,7 +592,7 @@ component DataTable { client function goToPage(next) { var target = Math.min(Math.max(1, next), pageCount()) - page = target + paginationPage = target output.pageChange({ page: target, pageSize: Number(perPage) || 10 }) reload() output.change(viewState()) @@ -602,7 +602,7 @@ component DataTable { // takes the Dropdown select detail directly. client function pickPageSize(detail) { perPage = Number(detail && detail.value) || 10 - page = 1 + paginationPage = 1 output.pageChange({ page: 1, pageSize: perPage }) reload() output.change(viewState()) @@ -613,7 +613,7 @@ component DataTable { // clicks. client function clearSearch() { query = "" - page = 1 + paginationPage = 1 output.search({ query: "" }) reload() } diff --git a/packages/ui/test/ui.test.ts b/packages/ui/test/ui.test.ts index facaf20f..9a27d045 100644 --- a/packages/ui/test/ui.test.ts +++ b/packages/ui/test/ui.test.ts @@ -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 () => { const source = readFileSync(uiComponentPath("Chart"), "utf8"); 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 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 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(); expect(root.querySelector(".wire-tree-view__group")?.getAttribute("data-show")).toBe("true"); (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 () => { - 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 confettiEvents: string[] = []; 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)); 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", { configurable: true, value: { writeText: () => Promise.resolve() }, }); const clipboardRoot = clipboard.querySelector('[data-ui-component="Clipboard"]') as HTMLElement; 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(); await new Promise((resolve) => setTimeout(resolve, 0)); expect(clipboardEvents).toEqual(["copy", "success"]); diff --git a/scripts/generate-ui-component-reference.mjs b/scripts/generate-ui-component-reference.mjs index 89181b2e..2ff62d8e 100644 --- a/scripts/generate-ui-component-reference.mjs +++ b/scripts/generate-ui-component-reference.mjs @@ -1,5 +1,6 @@ import { readdirSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; +import prettier from "prettier"; const uiRoot = join(import.meta.dirname, "..", "packages", "ui"); const componentsDir = join(uiRoot, "components"); @@ -11,17 +12,20 @@ function normalizeNewlines(source) { 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"); // Do not rewrite a generated file when only its working-tree line endings // differ. This keeps release verification clean on Windows CRLF checkouts // while still rewriting files whose generated content is genuinely stale. - if (normalizeNewlines(current) === normalizeNewlines(source)) { + if (normalizeNewlines(current) === normalizeNewlines(formatted)) { return false; } - writeFileSync(path, source); + writeFileSync(path, formatted); return true; }