From 9528c55f63818c9d7ae820f2e700384f936dcf48 Mon Sep 17 00:00:00 2001 From: owjs3901 Date: Fri, 20 Mar 2026 20:26:27 +0900 Subject: [PATCH] Fix property issue --- bun.lock | 64 +++++++++---------- package.json | 4 +- src/code-impl.ts | 6 +- src/codegen/Codegen.ts | 13 ++-- src/codegen/props/selector.ts | 16 +++-- src/codegen/responsive/ResponsiveCodegen.ts | 25 +++++--- .../extract-instance-variant-props.test.ts | 14 ++++ ...get-component-property-definitions.test.ts | 41 ++++++++++++ .../utils/extract-instance-variant-props.ts | 13 +++- .../get-component-property-definitions.ts | 21 ++++++ 10 files changed, 156 insertions(+), 61 deletions(-) create mode 100644 src/codegen/utils/__tests__/get-component-property-definitions.test.ts create mode 100644 src/codegen/utils/get-component-property-definitions.ts diff --git a/bun.lock b/bun.lock index 2fb675b..31203ff 100644 --- a/bun.lock +++ b/bun.lock @@ -10,8 +10,8 @@ "devDependencies": { "@biomejs/biome": "^2.4", "@figma/plugin-typings": "^1.123", - "@rspack/cli": "^1.7.8", - "@rspack/core": "^1.7.8", + "@rspack/cli": "^1.7.9", + "@rspack/core": "^1.7.9", "@types/bun": "^1.3", "husky": "^9.1", "typescript": "^5.9", @@ -19,29 +19,29 @@ }, }, "packages": { - "@biomejs/biome": ["@biomejs/biome@2.4.7", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.7", "@biomejs/cli-darwin-x64": "2.4.7", "@biomejs/cli-linux-arm64": "2.4.7", "@biomejs/cli-linux-arm64-musl": "2.4.7", "@biomejs/cli-linux-x64": "2.4.7", "@biomejs/cli-linux-x64-musl": "2.4.7", "@biomejs/cli-win32-arm64": "2.4.7", "@biomejs/cli-win32-x64": "2.4.7" }, "bin": { "biome": "bin/biome" } }, "sha512-vXrgcmNGZ4lpdwZSpMf1hWw1aWS6B+SyeSYKTLrNsiUsAdSRN0J4d/7mF3ogJFbIwFFSOL3wT92Zzxia/d5/ng=="], + "@biomejs/biome": ["@biomejs/biome@2.4.8", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.8", "@biomejs/cli-darwin-x64": "2.4.8", "@biomejs/cli-linux-arm64": "2.4.8", "@biomejs/cli-linux-arm64-musl": "2.4.8", "@biomejs/cli-linux-x64": "2.4.8", "@biomejs/cli-linux-x64-musl": "2.4.8", "@biomejs/cli-win32-arm64": "2.4.8", "@biomejs/cli-win32-x64": "2.4.8" }, "bin": { "biome": "bin/biome" } }, "sha512-ponn0oKOky1oRXBV+rlSaUlixUxf1aZvWC19Z41zBfUOUesthrQqL3OtiAlSB1EjFjyWpn98Q64DHelhA6jNlA=="], - "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Oo0cF5mHzmvDmTXw8XSjhCia8K6YrZnk7aCS54+/HxyMdZMruMO3nfpDsrlar/EQWe41r1qrwKiCa2QDYHDzWA=="], + "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ARx0tECE8I7S2C2yjnWYLNbBdDoPdq3oyNLhMglmuctThwUsuzFWRKrHmIGwIRWKz0Mat9DuzLEDp52hGnrxGQ=="], - "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-I+cOG3sd/7HdFtvDSnF9QQPrWguUH7zrkIMMykM3PtfWU9soTcS2yRb9Myq6MHmzbeCT08D1UmY+BaiMl5CcoQ=="], + "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-Jg9/PsB9vDCJlANE8uhG7qDhb5w0Ix69D7XIIc8IfZPUoiPrbLm33k2Ig3NOJ/7nb3UbesFz3D1aDKm9DvzjhQ=="], - "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-om6FugwmibzfP/6ALj5WRDVSND4H2G9X0nkI1HZpp2ySf9lW2j0X68oQSaHEnls6666oy4KDsc5RFjT4m0kV0w=="], + "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-5CdrsJct76XG2hpKFwXnEtlT1p+4g4yV+XvvwBpzKsTNLO9c6iLlAxwcae2BJ7ekPGWjNGw9j09T5KGPKKxQig=="], - "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-I2NvM9KPb09jWml93O2/5WMfNR7Lee5Latag1JThDRMURVhPX74p9UDnyTw3Ae6cE1DgXfw7sqQgX7rkvpc0vw=="], + "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-Zo9OhBQDJ3IBGPlqHiTISloo5H0+FBIpemqIJdW/0edJ+gEcLR+MZeZozcUyz3o1nXkVA7++DdRKQT0599j9jA=="], - "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.7", "", { "os": "linux", "cpu": "x64" }, "sha512-bV8/uo2Tj+gumnk4sUdkerWyCPRabaZdv88IpbmDWARQQoA/Q0YaqPz1a+LSEDIL7OfrnPi9Hq1Llz4ZIGyIQQ=="], + "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.8", "", { "os": "linux", "cpu": "x64" }, "sha512-PdKXspVEaMCQLjtZCn6vfSck/li4KX9KGwSDbZdgIqlrizJ2MnMcE3TvHa2tVfXNmbjMikzcfJpuPWH695yJrw=="], - "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.7", "", { "os": "linux", "cpu": "x64" }, "sha512-00kx4YrBMU8374zd2wHuRV5wseh0rom5HqRND+vDldJPrWwQw+mzd/d8byI9hPx926CG+vWzq6AeiT7Yi5y59g=="], + "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.8", "", { "os": "linux", "cpu": "x64" }, "sha512-Gi8quv8MEuDdKaPFtS2XjEnMqODPsRg6POT6KhoP+VrkNb+T2ywunVB+TvOU0LX1jAZzfBr+3V1mIbBhzAMKvw=="], - "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-hOUHBMlFCvDhu3WCq6vaBoG0dp0LkWxSEnEEsxxXvOa9TfT6ZBnbh72A/xBM7CBYB7WgwqboetzFEVDnMxelyw=="], + "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-LoFatS0tnHv6KkCVpIy3qZCih+MxUMvdYiPWLHRri7mhi2vyOOs8OrbZBcLTUEWCS+ktO72nZMy4F96oMhkOHQ=="], - "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.7", "", { "os": "win32", "cpu": "x64" }, "sha512-qEpGjSkPC3qX4ycbMUthXvi9CkRq7kZpkqMY1OyhmYlYLnANnooDQ7hDerM8+0NJ+DZKVnsIc07h30XOpt7LtQ=="], + "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.8", "", { "os": "win32", "cpu": "x64" }, "sha512-vAn7iXDoUbqFXqVocuq1sMYAd33p8+mmurqJkWl6CtIhobd/O6moe4rY5AJvzbunn/qZCdiDVcveqtkFh1e7Hg=="], "@discoveryjs/json-ext": ["@discoveryjs/json-ext@0.5.7", "", {}, "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw=="], - "@emnapi/core": ["@emnapi/core@1.9.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" } }, "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w=="], + "@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" } }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="], - "@emnapi/runtime": ["@emnapi/runtime@1.9.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw=="], + "@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="], "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="], @@ -93,31 +93,31 @@ "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], - "@rspack/binding": ["@rspack/binding@1.7.8", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.7.8", "@rspack/binding-darwin-x64": "1.7.8", "@rspack/binding-linux-arm64-gnu": "1.7.8", "@rspack/binding-linux-arm64-musl": "1.7.8", "@rspack/binding-linux-x64-gnu": "1.7.8", "@rspack/binding-linux-x64-musl": "1.7.8", "@rspack/binding-wasm32-wasi": "1.7.8", "@rspack/binding-win32-arm64-msvc": "1.7.8", "@rspack/binding-win32-ia32-msvc": "1.7.8", "@rspack/binding-win32-x64-msvc": "1.7.8" } }, "sha512-P4fbrQx5hRhAiC8TBTEMCTnNawrIzJLjWwAgrTwRxjgenpjNvimEkQBtSGrXOY+c+MV5Q74P+9wPvVWLKzRkQQ=="], + "@rspack/binding": ["@rspack/binding@1.7.9", "", { "optionalDependencies": { "@rspack/binding-darwin-arm64": "1.7.9", "@rspack/binding-darwin-x64": "1.7.9", "@rspack/binding-linux-arm64-gnu": "1.7.9", "@rspack/binding-linux-arm64-musl": "1.7.9", "@rspack/binding-linux-x64-gnu": "1.7.9", "@rspack/binding-linux-x64-musl": "1.7.9", "@rspack/binding-wasm32-wasi": "1.7.9", "@rspack/binding-win32-arm64-msvc": "1.7.9", "@rspack/binding-win32-ia32-msvc": "1.7.9", "@rspack/binding-win32-x64-msvc": "1.7.9" } }, "sha512-A56e0NdfNwbOSJoilMkxzaPuVYaKCNn1shuiwWnCIBmhV9ix1n9S1XvquDjkGyv+gCdR1+zfJBOa5DMB7htLHw=="], - "@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@1.7.8", "", { "os": "darwin", "cpu": "arm64" }, "sha512-KS6SRc+4VYRdX1cKr1j1HEuMNyEzt7onBS0rkenaiCRRYF0z4WNZNyZqRiuxgM3qZ3TISF7gdmgJQyd4ZB43ig=="], + "@rspack/binding-darwin-arm64": ["@rspack/binding-darwin-arm64@1.7.9", "", { "os": "darwin", "cpu": "arm64" }, "sha512-64dgstte0If5czi9bA/cpOe0ryY6wC9AIQRtyJ3DlOF6Tt+y9cKkmUoGu3V+WYaYIZRT7HNk8V7kL8amVjFTYw=="], - "@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@1.7.8", "", { "os": "darwin", "cpu": "x64" }, "sha512-uyXSDKLg2CtqIJrsJDlCqQH80YIPsCUiTToJ59cXAG3v4eke0Qbiv6d/+pV0h/mc0u4inAaSkr5dD18zkMIghw=="], + "@rspack/binding-darwin-x64": ["@rspack/binding-darwin-x64@1.7.9", "", { "os": "darwin", "cpu": "x64" }, "sha512-2QSLs3w4rLy4UUGVnIlkt6IlIKOzR1e0RPsq2FYQW6s3p9JrwRCtOeHohyh7EJSqF54dtfhe9UZSAwba3LqH1Q=="], - "@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@1.7.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-dD6gSHA18Uj0eqc1FCwwQ5IO5mIckrpYN4H4kPk9Pjau+1mxWvC4y5Lryz1Z8P/Rh1lnQ/wwGE0XL9nd80+LqQ=="], + "@rspack/binding-linux-arm64-gnu": ["@rspack/binding-linux-arm64-gnu@1.7.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-qhUGI/uVfvLmKWts4QkVHGL8yfUyJkblZs+OFD5Upa2y676EOsbQgWsCwX4xGB6Tv+TOzFP0SLh/UfO8ZfdE+w=="], - "@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@1.7.8", "", { "os": "linux", "cpu": "arm64" }, "sha512-m+uBi9mEVGkZ02PPOAYN2BSmmvc00XGa6v9CjV8qLpolpUXQIMzDNG+i1fD5SHp8LO+XWsZJOHypMsT0MzGTGw=="], + "@rspack/binding-linux-arm64-musl": ["@rspack/binding-linux-arm64-musl@1.7.9", "", { "os": "linux", "cpu": "arm64" }, "sha512-VjfmR1hgO9n3L6MaE5KG+DXSrrLVqHHOkVcOtS2LMq3bjMTwbBywY7ycymcLnX5KJsol8d3ZGYep6IfSOt3lFA=="], - "@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@1.7.8", "", { "os": "linux", "cpu": "x64" }, "sha512-IAPp2L3yS33MAEkcGn/I1gO+a+WExJHXz2ZlRlL2oFCUGpYi2ZQHyAcJ3o2tJqkXmdqsTiN+OjEVMd/RcLa24g=="], + "@rspack/binding-linux-x64-gnu": ["@rspack/binding-linux-x64-gnu@1.7.9", "", { "os": "linux", "cpu": "x64" }, "sha512-0kldV+3WTs/VYDWzxJ7K40hCW26IHtnk8xPK3whKoo1649rgeXXa0EdsU5P7hG8Ef5SWQjHHHZ/fuHYSO3Y6HA=="], - "@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@1.7.8", "", { "os": "linux", "cpu": "x64" }, "sha512-do/QNzb4GWdXCsipblDcroqRDR3BFcbyzpZpAw/3j9ajvEqsOKpdHZpILT2NZX/VahhjqfqB3k0kJVt3uK7UYQ=="], + "@rspack/binding-linux-x64-musl": ["@rspack/binding-linux-x64-musl@1.7.9", "", { "os": "linux", "cpu": "x64" }, "sha512-Gi4872cFtc2d83FKATR6Qcf2VBa/tFCqffI/IwRRl6Hx5FulEBqx+tH7gAuRVF693vrbXNxK+FQ+k4iEsEJxrw=="], - "@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@1.7.8", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.0.7" }, "cpu": "none" }, "sha512-mHtgYTpdhx01i0XNKFYBZyCjtv9YUe/sDfpD1QK4FytPFB+1VpYnmZiaJIMM77VpNsjxGAqWhmUYxi2P6jWifw=="], + "@rspack/binding-wasm32-wasi": ["@rspack/binding-wasm32-wasi@1.7.9", "", { "dependencies": { "@napi-rs/wasm-runtime": "1.0.7" }, "cpu": "none" }, "sha512-5QEzqo6EaolpuZmK6w/mgSueorgGnnzp7dJaAvBj6ECFIg/aLXhXXmWCWbxt7Ws2gKvG5/PgaxDqbUxYL51juA=="], - "@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@1.7.8", "", { "os": "win32", "cpu": "arm64" }, "sha512-Mkxg86F7kIT4pM9XvE/1LAGjK5NOQi/GJxKyyiKbUAeKM8XBUizVeNuvKR0avf2V5IDAIRXiH1SX8SpujMJteA=="], + "@rspack/binding-win32-arm64-msvc": ["@rspack/binding-win32-arm64-msvc@1.7.9", "", { "os": "win32", "cpu": "arm64" }, "sha512-MMqvcrIc8aOqTuHjWkjdzilvoZ3Hv07Od0Foogiyq3JMudsS3Wcmh7T1dFerGg19MOJcRUeEkrg2NQOMOQ6xDA=="], - "@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@1.7.8", "", { "os": "win32", "cpu": "ia32" }, "sha512-VmTOZ/X7M85lKFNwb2qJpCRzr4SgO42vucq/X7Uz1oSoTPAf8UUMNdi7BPnu+D4lgy6l8PwV804ZyHO3gGsvPA=="], + "@rspack/binding-win32-ia32-msvc": ["@rspack/binding-win32-ia32-msvc@1.7.9", "", { "os": "win32", "cpu": "ia32" }, "sha512-4kYYS+NZ2CuNbKjq40yB/UEyB51o1PHj5wpr+Y943oOJXpEKWU2Q4vkF8VEohPEcnA9cKVotYCnqStme+02suA=="], - "@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@1.7.8", "", { "os": "win32", "cpu": "x64" }, "sha512-BK0I4HAwp/yQLnmdJpUtGHcht3x11e9fZwyaiMzznznFc+Oypbf+FS5h+aBgpb53QnNkPpdG7MfAPoKItOcU8A=="], + "@rspack/binding-win32-x64-msvc": ["@rspack/binding-win32-x64-msvc@1.7.9", "", { "os": "win32", "cpu": "x64" }, "sha512-1g+QyXXvs+838Un/4GaUvJfARDGHMCs15eXDYWBl5m/Skubyng8djWAgr6ag1+cVoJZXCPOvybTItcblWF3gbQ=="], - "@rspack/cli": ["@rspack/cli@1.7.8", "", { "dependencies": { "@discoveryjs/json-ext": "^0.5.7", "@rspack/dev-server": "~1.1.5", "exit-hook": "^4.0.0", "webpack-bundle-analyzer": "4.10.2" }, "peerDependencies": { "@rspack/core": "^1.0.0-alpha || ^1.x" }, "bin": { "rspack": "bin/rspack.js" } }, "sha512-CyOD12ecwkVsvzX1peVo+pZO6JoDzxD3nHC5yBcwrWrntsAcp+e5RNHjz3yJuLa/Mta1Mgr3EZzv7BMBQf14ew=="], + "@rspack/cli": ["@rspack/cli@1.7.9", "", { "dependencies": { "@discoveryjs/json-ext": "^0.5.7", "@rspack/dev-server": "~1.1.5", "exit-hook": "^4.0.0", "webpack-bundle-analyzer": "4.10.2" }, "peerDependencies": { "@rspack/core": "^1.0.0-alpha || ^1.x" }, "bin": { "rspack": "bin/rspack.js" } }, "sha512-VwJIO8ZUGnU5v38O2Fp3KczoYVaDy/kA0rBWhoUNhfdlwyVx3ZiA1VnIYF3XtXNlur6YqT2g7Y+KA1cX8qK5zw=="], - "@rspack/core": ["@rspack/core@1.7.8", "", { "dependencies": { "@module-federation/runtime-tools": "0.22.0", "@rspack/binding": "1.7.8", "@rspack/lite-tapable": "1.1.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" }, "optionalPeers": ["@swc/helpers"] }, "sha512-kT6yYo8xjKoDfM7iB8N9AmN9DJIlrs7UmQDbpTu1N4zaZocN1/t2fIAWOKjr5+3eJlZQR2twKZhDVHNLbLPjOw=="], + "@rspack/core": ["@rspack/core@1.7.9", "", { "dependencies": { "@module-federation/runtime-tools": "0.22.0", "@rspack/binding": "1.7.9", "@rspack/lite-tapable": "1.1.0" }, "peerDependencies": { "@swc/helpers": ">=0.5.1" }, "optionalPeers": ["@swc/helpers"] }, "sha512-VHuSKvRkuv42Ya+TxEGO0LE0r9+8P4tKGokmomj4R1f/Nu2vtS3yoaIMfC4fR6VuHGd3MZ+KTI0cNNwHfFcskw=="], "@rspack/dev-server": ["@rspack/dev-server@1.1.5", "", { "dependencies": { "chokidar": "^3.6.0", "http-proxy-middleware": "^2.0.9", "p-retry": "^6.2.0", "webpack-dev-server": "5.2.2", "ws": "^8.18.0" }, "peerDependencies": { "@rspack/core": "*" } }, "sha512-cwz0qc6iqqoJhyWqxP7ZqE2wyYNHkBMQUXxoQ0tNoZ4YNRkDyQ4HVJ/3oPSmMKbvJk/iJ16u7xZmwG6sK47q/A=="], @@ -129,7 +129,7 @@ "@types/bonjour": ["@types/bonjour@3.5.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ=="], - "@types/bun": ["@types/bun@1.3.10", "", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="], + "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="], "@types/connect": ["@types/connect@3.4.38", "", { "dependencies": { "@types/node": "*" } }, "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug=="], @@ -195,7 +195,7 @@ "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "bun-types": ["bun-types@1.3.10", "", { "dependencies": { "@types/node": "*" } }, "sha512-tcpfCCl6XWo6nCVnpcVrxQ+9AYN1iqMIzgrSKYMB/fjLtV2eyAVEg7AxQJuCq/26R6HpKWykQXuSOq/21RYcbg=="], + "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="], "bundle-name": ["bundle-name@4.1.0", "", { "dependencies": { "run-applescript": "^7.0.0" } }, "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q=="], @@ -379,7 +379,7 @@ "mime": ["mime@1.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="], - "mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], "mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], @@ -485,7 +485,7 @@ "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], - "thingies": ["thingies@2.5.0", "", { "peerDependencies": { "tslib": "^2" } }, "sha512-s+2Bwztg6PhWUD7XMfeYm5qliDdSiZm7M7n8KjTkIsm3l/2lgVRc2/Gx/v+ZX8lT4FMA+i8aQvhcWylldc+ZNw=="], + "thingies": ["thingies@2.6.0", "", { "peerDependencies": { "tslib": "^2" } }, "sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg=="], "thunky": ["thunky@1.1.0", "", {}, "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="], @@ -547,6 +547,8 @@ "express/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + "proxy-addr/ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], "send/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], @@ -580,7 +582,5 @@ "spdy-transport/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], "spdy/debug/ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - - "webpack-dev-middleware/mime-types/mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], } } diff --git a/package.json b/package.json index 43af250..5ba116e 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "license": "", "devDependencies": { "@figma/plugin-typings": "^1.123", - "@rspack/cli": "^1.7.8", - "@rspack/core": "^1.7.8", + "@rspack/cli": "^1.7.9", + "@rspack/core": "^1.7.9", "husky": "^9.1", "typescript": "^5.9", diff --git a/src/code-impl.ts b/src/code-impl.ts index 4441c14..b43fe40 100644 --- a/src/code-impl.ts +++ b/src/code-impl.ts @@ -11,6 +11,7 @@ import { } from './codegen/props/selector' import { ResponsiveCodegen } from './codegen/responsive/ResponsiveCodegen' import { isReservedVariantKey } from './codegen/utils/extract-instance-variant-props' +import { getComponentPropertyDefinitions } from './codegen/utils/get-component-property-definitions' import { nodeProxyTracker } from './codegen/utils/node-proxy' import { perfEnd, perfReport, perfReset, perfStart } from './codegen/utils/perf' import { resetVariableCache } from './codegen/utils/variable-cache' @@ -111,7 +112,7 @@ export function generateComponentUsage(node: SceneNode): string | null { (node as ComponentNode).parent?.type === 'COMPONENT_SET' ? ((node as ComponentNode).parent as ComponentSetNode) : null - const defs = parentSet?.componentPropertyDefinitions + const defs = getComponentPropertyDefinitions(parentSet) let textEntry: { key: string; value: string } | null = null let textCount = 0 if (defs) { @@ -162,8 +163,7 @@ export function generateComponentUsage(node: SceneNode): string | null { } if (node.type === 'COMPONENT_SET') { - const defs = (node as ComponentSetNode).componentPropertyDefinitions - if (!defs) return `<${componentName} />` + const defs = getComponentPropertyDefinitions(node as ComponentSetNode) const entries: { key: string; value: string; type: string }[] = [] let textEntry: { key: string; value: string } | null = null diff --git a/src/codegen/Codegen.ts b/src/codegen/Codegen.ts index 073ba48..8ae800c 100644 --- a/src/codegen/Codegen.ts +++ b/src/codegen/Codegen.ts @@ -10,6 +10,7 @@ import type { ComponentTree, NodeTree } from './types' import { checkAssetNode } from './utils/check-asset-node' import { checkSameColor } from './utils/check-same-color' import { extractInstanceVariantProps } from './utils/extract-instance-variant-props' +import { getComponentPropertyDefinitions } from './utils/get-component-property-definitions' import { getDevupComponentByNode, getDevupComponentByProps, @@ -639,10 +640,9 @@ export class Codegen { // Collect INSTANCE_SWAP and BOOLEAN property definitions for slot/condition detection. const parentSet = node.parent?.type === 'COMPONENT_SET' ? node.parent : null - const propDefs = - parentSet?.componentPropertyDefinitions || - node.componentPropertyDefinitions || - {} + const propDefs = parentSet + ? getComponentPropertyDefinitions(parentSet) + : getComponentPropertyDefinitions(node) const instanceSwapSlots = new Map() const booleanSlots = new Map() const textSlots = new Map() @@ -758,8 +758,9 @@ export class Codegen { */ hasViewportVariant(): boolean { if (this.node.type !== 'COMPONENT_SET') return false - for (const key in (this.node as ComponentSetNode) - .componentPropertyDefinitions) { + for (const key in getComponentPropertyDefinitions( + this.node as ComponentSetNode, + )) { if (key.toLowerCase() === 'viewport') return true } return false diff --git a/src/codegen/props/selector.ts b/src/codegen/props/selector.ts index 91845ab..bec5c6a 100644 --- a/src/codegen/props/selector.ts +++ b/src/codegen/props/selector.ts @@ -1,4 +1,5 @@ import { fmtPct } from '../utils/fmtPct' +import { getComponentPropertyDefinitions } from '../utils/get-component-property-definitions' import { perfEnd, perfStart } from '../utils/perf' import { getProps } from '.' @@ -141,7 +142,8 @@ async function computeSelectorProps(node: ComponentSetNode): Promise<{ variants: Record variantComments: Record }> { - const hasEffect = !!node.componentPropertyDefinitions.effect + const propDefs = getComponentPropertyDefinitions(node) + const hasEffect = !!propDefs.effect const tSelector = perfStart() // Pre-filter: only call expensive getProps() on children with non-default effects. // The effect/trigger check is a cheap property read — skip children that would be @@ -169,7 +171,7 @@ async function computeSelectorProps(node: ComponentSetNode): Promise<{ variants: Record variantComments: Record } = { props: {}, variants: {}, variantComments: {} } - const defs = node.componentPropertyDefinitions + const defs = propDefs for (const name in defs) { if (name === 'effect' || name === 'viewport') continue const definition = defs[name] @@ -233,7 +235,8 @@ export async function getSelectorPropsForGroup( variantFilter: Record, viewportValue?: string, ): Promise> { - const hasEffect = !!componentSet.componentPropertyDefinitions.effect + const setDefs = getComponentPropertyDefinitions(componentSet) + const hasEffect = !!setDefs.effect if (!hasEffect) return {} // Build cache key from componentSet.id + filter + viewport @@ -269,9 +272,10 @@ async function computeSelectorPropsForGroup( viewportValue?: string, ): Promise> { // Find viewport key if needed - const viewportKey = Object.keys( - componentSet.componentPropertyDefinitions, - ).find((key) => key.toLowerCase() === 'viewport') + const groupDefs = getComponentPropertyDefinitions(componentSet) + const viewportKey = Object.keys(groupDefs).find( + (key) => key.toLowerCase() === 'viewport', + ) // Filter components matching the variant filter (and viewport if specified) const matchingComponents = componentSet.children.filter((child) => { diff --git a/src/codegen/responsive/ResponsiveCodegen.ts b/src/codegen/responsive/ResponsiveCodegen.ts index 03eb456..223c5a1 100644 --- a/src/codegen/responsive/ResponsiveCodegen.ts +++ b/src/codegen/responsive/ResponsiveCodegen.ts @@ -6,6 +6,7 @@ import { } from '../props/selector' import { renderComponent, renderNode } from '../render' import type { NodeTree, Props } from '../types' +import { getComponentPropertyDefinitions } from '../utils/get-component-property-definitions' import { paddingLeftMultiline } from '../utils/padding-left-multiline' import { perfEnd, perfStart } from '../utils/perf' import { @@ -399,9 +400,10 @@ export class ResponsiveCodegen { componentName: string, ): Promise> { // Find viewport and effect variant keys + const viewportDefs = getComponentPropertyDefinitions(componentSet) let viewportKey: string | undefined let effectKey: string | undefined - for (const key in componentSet.componentPropertyDefinitions) { + for (const key in viewportDefs) { const lower = key.toLowerCase() if (lower === 'viewport') viewportKey = key else if (lower === 'effect') effectKey = key @@ -413,8 +415,8 @@ export class ResponsiveCodegen { // Get variants excluding viewport const variants: Record = {} - for (const name in componentSet.componentPropertyDefinitions) { - const definition = componentSet.componentPropertyDefinitions[name] + for (const name in viewportDefs) { + const definition = viewportDefs[name] const lowerName = name.toLowerCase() if (lowerName !== 'viewport' && lowerName !== 'effect') { const sanitizedName = sanitizePropertyName(name) @@ -550,9 +552,10 @@ export class ResponsiveCodegen { const tTotal = perfStart() // Find viewport and effect variant keys + const variantDefs = getComponentPropertyDefinitions(componentSet) let viewportKey: string | undefined let effectKey: string | undefined - for (const key in componentSet.componentPropertyDefinitions) { + for (const key in variantDefs) { const lower = key.toLowerCase() if (lower === 'viewport') viewportKey = key else if (lower === 'effect') effectKey = key @@ -563,8 +566,8 @@ export class ResponsiveCodegen { const variants: Record = {} // Map from original name to sanitized name const variantKeyToSanitized: Record = {} - for (const name in componentSet.componentPropertyDefinitions) { - const definition = componentSet.componentPropertyDefinitions[name] + for (const name in variantDefs) { + const definition = variantDefs[name] if (definition.type === 'VARIANT') { const lowerName = name.toLowerCase() // Exclude both viewport and effect from variant keys @@ -794,8 +797,9 @@ export class ResponsiveCodegen { // Collect BOOLEAN and INSTANCE_SWAP props for the interface // (effect is handled via pseudo-selectors, VARIANT keys don't exist in effect-only path) const variants: Record = {} - for (const name in componentSet.componentPropertyDefinitions) { - const definition = componentSet.componentPropertyDefinitions[name] + const effectDefs = getComponentPropertyDefinitions(componentSet) + for (const name in effectDefs) { + const definition = effectDefs[name] if (definition.type === 'INSTANCE_SWAP') { variants[sanitizePropertyName(name)] = 'React.ReactNode' } else if (definition.type === 'BOOLEAN') { @@ -831,8 +835,9 @@ export class ResponsiveCodegen { } // Check if componentSet has effect variant (pseudo-selector) + const groupVariantDefs = getComponentPropertyDefinitions(componentSet) let hasEffect = false - for (const key in componentSet.componentPropertyDefinitions) { + for (const key in groupVariantDefs) { if (key.toLowerCase() === 'effect') { hasEffect = true break @@ -905,7 +910,7 @@ export class ResponsiveCodegen { if (hasEffect) { const effectValue = variantProps[ - Object.keys(componentSet.componentPropertyDefinitions).find( + Object.keys(groupVariantDefs).find( (k) => k.toLowerCase() === 'effect', ) || '' ] diff --git a/src/codegen/utils/__tests__/extract-instance-variant-props.test.ts b/src/codegen/utils/__tests__/extract-instance-variant-props.test.ts index 7b43bde..d46d6a2 100644 --- a/src/codegen/utils/__tests__/extract-instance-variant-props.test.ts +++ b/src/codegen/utils/__tests__/extract-instance-variant-props.test.ts @@ -151,6 +151,20 @@ describe('extractInstanceVariantProps', () => { expect(result.Viewport).toBeUndefined() }) + test('returns empty object when componentProperties getter throws', () => { + const node = { + get componentProperties(): never { + throw new Error( + 'in get_componentProperties: Component set for node has existing errors', + ) + }, + } as unknown as InstanceNode + + const result = extractInstanceVariantProps(node) + + expect(result).toEqual({}) + }) + test('filters out both effect and viewport but keeps other variants', () => { const node = { componentProperties: { diff --git a/src/codegen/utils/__tests__/get-component-property-definitions.test.ts b/src/codegen/utils/__tests__/get-component-property-definitions.test.ts new file mode 100644 index 0000000..253ce19 --- /dev/null +++ b/src/codegen/utils/__tests__/get-component-property-definitions.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, test } from 'bun:test' +import { getComponentPropertyDefinitions } from '../get-component-property-definitions' + +describe('getComponentPropertyDefinitions', () => { + test('returns definitions from a valid node', () => { + const defs = { + status: { + type: 'VARIANT', + defaultValue: 'active', + variantOptions: ['active', 'inactive'], + }, + } + const node = { + componentPropertyDefinitions: defs, + } as unknown as ComponentSetNode + + expect(getComponentPropertyDefinitions(node)).toBe( + defs as ComponentPropertyDefinitions, + ) + }) + + test('returns empty object when node is null', () => { + expect(getComponentPropertyDefinitions(null)).toEqual({}) + }) + + test('returns empty object when node is undefined', () => { + expect(getComponentPropertyDefinitions(undefined)).toEqual({}) + }) + + test('returns empty object when getter throws', () => { + const node = { + get componentPropertyDefinitions(): never { + throw new Error( + 'in get_componentPropertyDefinitions: Component set has existing errors', + ) + }, + } as unknown as ComponentSetNode + + expect(getComponentPropertyDefinitions(node)).toEqual({}) + }) +}) diff --git a/src/codegen/utils/extract-instance-variant-props.ts b/src/codegen/utils/extract-instance-variant-props.ts index 0017c24..8397f07 100644 --- a/src/codegen/utils/extract-instance-variant-props.ts +++ b/src/codegen/utils/extract-instance-variant-props.ts @@ -30,11 +30,20 @@ export function extractInstanceVariantProps( ): Record { const variantProps: Record = {} - if (!node.componentProperties) { + let componentProperties: InstanceNode['componentProperties'] + try { + componentProperties = node.componentProperties + } catch { + // Figma throws when the component set has validation errors + // (e.g. duplicate variant names, missing properties). return variantProps } - for (const [key, prop] of Object.entries(node.componentProperties)) { + if (!componentProperties) { + return variantProps + } + + for (const [key, prop] of Object.entries(componentProperties)) { if (isReservedVariantKey(key)) continue const sanitizedKey = sanitizePropertyName(key) if (prop.type === 'VARIANT') { diff --git a/src/codegen/utils/get-component-property-definitions.ts b/src/codegen/utils/get-component-property-definitions.ts new file mode 100644 index 0000000..f97678c --- /dev/null +++ b/src/codegen/utils/get-component-property-definitions.ts @@ -0,0 +1,21 @@ +/** + * Safely access componentPropertyDefinitions on a node. + * Figma's getter throws when the component set has validation errors + * (e.g. duplicate variant names, missing properties). + * Returns an empty object on error so callers can iterate safely. + */ +export function getComponentPropertyDefinitions( + node: ComponentSetNode | ComponentNode | null | undefined, +): ComponentSetNode['componentPropertyDefinitions'] { + if (!node) { + return {} as ComponentSetNode['componentPropertyDefinitions'] + } + try { + return ( + node.componentPropertyDefinitions || + ({} as ComponentSetNode['componentPropertyDefinitions']) + ) + } catch { + return {} as ComponentSetNode['componentPropertyDefinitions'] + } +}