{"_id":"@charcuterie/eslint-config","_rev":"10-6a2432eb3375de8246cdb71942454e22","name":"@charcuterie/eslint-config","dist-tags":{"latest":"1.7.1"},"versions":{"0.1.0":{"name":"@charcuterie/eslint-config","version":"0.1.0","license":"MIT","_id":"@charcuterie/eslint-config@0.1.0","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"499847de1700baba3440061e917af33fbe2b7f88","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-0.1.0.tgz","fileCount":13,"integrity":"sha512-oiullbG1SvWVIeQmNzRnKonhcUCh0M1bgAQhVstbGbI5o7BLEMWMWup4Oqy9f1qBg+WQOYdHZPLweXNDaFPXOg==","signatures":[{"sig":"MEQCICMxzDOBH6j7/XiGUrlqL8HjvWrOabX9EN3BGXso8dfhAiADO7IQVtV42M5qsKPjY5nEqK6+fd6F4iA1q07fkOn22w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21135},"main":"./src/index.js","type":"module","_from":"file:/tmp/eslint-config.tgz","exports":{".":"./src/index.js","./*":"./src/*"},"scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"_npmUser":{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"},"_resolved":"/tmp/eslint-config.tgz","_integrity":"sha512-oiullbG1SvWVIeQmNzRnKonhcUCh0M1bgAQhVstbGbI5o7BLEMWMWup4Oqy9f1qBg+WQOYdHZPLweXNDaFPXOg==","repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.16.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10","typescript-eslint":">=8"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_0.1.0_1785472265753_0.763312125476479","host":"s3://npm-registry-packages-npm-production"}},"1.0.0":{"name":"@charcuterie/eslint-config","version":"1.0.0","license":"MIT","_id":"@charcuterie/eslint-config@1.0.0","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"6c5428602b3b889cd3fa2c4096c29eac77198f9f","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-1.0.0.tgz","fileCount":12,"integrity":"sha512-Sxa/Lumumoy7QTkmS49pMsLPvj4XYwmxm6j6FM7cjlMb0sQPpArppUJV5z9qF/E5oA5Eka3VFnd/hC09SgmrFQ==","signatures":[{"sig":"MEQCIA0TJYqzs7quT1PmUTZtBgktDjmGO+UovqdD6iBi33R+AiBTALy7qThlIxCgWYrmiB6Q+3bBoWfoFJZQqVnHHXzbZg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@charcuterie%2feslint-config@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":20841},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js","./*":"./src/*"},"scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7b77db8c-1558-47d7-8bcb-a587df645791"}},"repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.16.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10","typescript-eslint":">=8"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_1.0.0_1785684129935_0.561110946754642","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@charcuterie/eslint-config","version":"1.1.0","license":"MIT","_id":"@charcuterie/eslint-config@1.1.0","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"c8ca75c1c30cce83f7e66451d5c20b6d5d4368b8","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-1.1.0.tgz","fileCount":18,"integrity":"sha512-+NAyKhxR6E5ZgSOYyyk8PxoNXydJeH1CWuS1zgHa8ztjIc5ttAhz/nH3agiyruuQI8wqgDNsW+HVZw5SS/OHrg==","signatures":[{"sig":"MEUCIQDcTZB/ygvFLo9wZbtisMt742VvJ2mygCHbvOJtEgDz4wIgTb1/MoW/ru5Bk/yy1wEe8fZ6PPeZpJvpfFL8nHhiw5s=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@charcuterie%2feslint-config@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":56525},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js","./*":"./src/*"},"scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7b77db8c-1558-47d7-8bcb-a587df645791"}},"repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.19.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"_nodeVersion":"26.7.0","dependencies":{"eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10","typescript-eslint":">=8"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_1.1.0_1786351242964_0.8261070168960241","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@charcuterie/eslint-config","version":"1.2.0","license":"MIT","_id":"@charcuterie/eslint-config@1.2.0","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"7befb3ca0485f973ca3373ab6d6e671624b98721","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-1.2.0.tgz","fileCount":18,"integrity":"sha512-sBwp1At7ulDokyjCUDyeowvVCEGJo75k/s0vCius/IuVDByTacB4oXypbjJezAGP3bYOvOqyrhluc0pa2lqU7w==","signatures":[{"sig":"MEYCIQCfZ2/oe4629NI7TCsiety2YgQxrpeKz0sR8OKrf40djwIhAN/ly0djJWTmdw52G3yXG7nenV2N0z//AFEO7y8jwrvu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@charcuterie%2feslint-config@1.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":57518},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js","./*":"./src/*"},"scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7b77db8c-1558-47d7-8bcb-a587df645791"}},"repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.19.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"_nodeVersion":"26.7.0","dependencies":{"eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10","typescript-eslint":">=8"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_1.2.0_1786442568637_0.28664347217904607","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@charcuterie/eslint-config","version":"1.3.0","license":"MIT","_id":"@charcuterie/eslint-config@1.3.0","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"b657f12730eb9c174477214108788ac741c6f2fe","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-1.3.0.tgz","fileCount":25,"integrity":"sha512-78peMzKdz+sy7rbxn9E/mIduDBu76IabxO5glHH28TKxEXu2f2Hoi2AOp0Mo2xKFv2dq3avIn0YjSWSy/owW0w==","signatures":[{"sig":"MEUCIQC2D66kT9ImM0ZPbnYCzU3yaNq5aWFTe5tG+UG9dxc0AAIgfG9xj9LZpM4IP9bUxvqlNE6iSNYBImpzyS8t734+dp4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@charcuterie%2feslint-config@1.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":99185},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js","./*":"./src/*"},"scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7b77db8c-1558-47d7-8bcb-a587df645791"}},"repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.19.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"_nodeVersion":"26.7.0","dependencies":{"eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10","typescript-eslint":">=8"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_1.3.0_1786597518743_0.3253314973922037","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@charcuterie/eslint-config","version":"1.4.0","license":"MIT","_id":"@charcuterie/eslint-config@1.4.0","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"4d9bf810e42f98b8cf6741865f1325cbeb4b5770","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-1.4.0.tgz","fileCount":25,"integrity":"sha512-a9PfahojkttWCn8IW+6CksU9SXtsUmSY7acCETbQkiGie+y+B6AZsGeWwW86maF/irNW7DKwI+w86izoGfG8YA==","signatures":[{"sig":"MEYCIQD4MxFyQW71gTHdWveHbE33BJ8qDWTlxmRPMI8EbkY0nAIhAL3aPmXcHhAPGfxM+6bFwa2IALicV2w2PhwXuS14vJXW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@charcuterie%2feslint-config@1.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":100258},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js","./*":"./src/*"},"scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7b77db8c-1558-47d7-8bcb-a587df645791"}},"repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.19.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"_nodeVersion":"26.7.0","dependencies":{"eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10","typescript-eslint":">=8"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_1.4.0_1787285875808_0.7637823919846576","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"@charcuterie/eslint-config","version":"1.5.0","license":"MIT","_id":"@charcuterie/eslint-config@1.5.0","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"298780d07bab122e171b022762e6f595f5b2da98","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-1.5.0.tgz","fileCount":27,"integrity":"sha512-q94Lgf+qVeZT9Tf3NPt2ubGmA6Q+OyD+tCest0Bs6gKaI1OYGsGpUhxSWXROFZCjA7B34KJS45qHTTlRRiBhWQ==","signatures":[{"sig":"MEQCICScjitV+iV5ErcdcqdAWWAiU3DwpohkglRjcHJpQ5DDAiBBhgc2b7q+yuwQZnw6AIcYy2ss4sSocZ8H+p/jk0/CBw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@charcuterie%2feslint-config@1.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":119566},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js","./*":"./src/*"},"scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7b77db8c-1558-47d7-8bcb-a587df645791"}},"repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.19.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"_nodeVersion":"26.7.0","dependencies":{"typescript-eslint":"^8.59.2","eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_1.5.0_1787292480388_0.20346933235532294","host":"s3://npm-registry-packages-npm-production"}},"1.6.0":{"name":"@charcuterie/eslint-config","version":"1.6.0","license":"MIT","_id":"@charcuterie/eslint-config@1.6.0","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"9e85a199bce2050a84ef7bfe6fc24806a4dd90f6","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-1.6.0.tgz","fileCount":27,"integrity":"sha512-OVtOsKzggX17h5MBmajL2ZmkGUMcagqjlSrjnGA7I+yehm2Zii5zR8m4L5dxEy7kyBaZ65JVTubUVXHpVIU0Tg==","signatures":[{"sig":"MEUCIHAkTYyHWC0xY7taENCR24n465KYBRGD7ozfKjuyac38AiEAxHRCdMN9eRNkVWsQujMs7XjilzeV/4siqZwAuuxVqCA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@charcuterie%2feslint-config@1.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":122725},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js","./*":"./src/*"},"scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7b77db8c-1558-47d7-8bcb-a587df645791"}},"repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.19.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"_nodeVersion":"26.7.0","dependencies":{"typescript-eslint":"^8.59.2","eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_1.6.0_1787298342341_0.7309412593570077","host":"s3://npm-registry-packages-npm-production"}},"1.7.0":{"name":"@charcuterie/eslint-config","version":"1.7.0","license":"MIT","_id":"@charcuterie/eslint-config@1.7.0","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"7e35d1fa16d35dc53af9d9368d44f19f08c03aaa","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-1.7.0.tgz","fileCount":29,"integrity":"sha512-v4SKywRQ0MwuwybdhK0KMHYofc50MwSejE+JoWO8OEuj+CWn4/T2cbT3LT8YdCoBQTNk2wi/bAUK/TRklIsiGg==","signatures":[{"sig":"MEYCIQDzuiOuupsucMIyX+hHTeWejQtBJ50w9TKdJO7PHh5ziwIhAN8POYSxpL+cUvWJeNMeQSfFvTj0drj4vhGGQm+LPm2C","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@charcuterie%2feslint-config@1.7.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":127942},"main":"./src/index.js","type":"module","exports":{".":"./src/index.js","./*":"./src/*"},"scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7b77db8c-1558-47d7-8bcb-a587df645791"}},"repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.19.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"_nodeVersion":"26.7.0","dependencies":{"typescript-eslint":"^8.59.2","eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10"},"_npmOperationalInternal":{"tmp":"tmp/eslint-config_1.7.0_1787299272680_0.1144744942921947","host":"s3://npm-registry-packages-npm-production"}},"1.7.1":{"_id":"@charcuterie/eslint-config@1.7.1","bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"dist":{"shasum":"84066cffa662fe1fdce65f3eef310be21177ac56","tarball":"https://registry.npmjs.org/@charcuterie/eslint-config/-/eslint-config-1.7.1.tgz","fileCount":29,"integrity":"sha512-cUHIrd4UAbhnFgOh5gmZ6xxhqCAJZiKVyLTbsk8++gVK7bmWX52Ob2BJdbOMj0jxYgXm+p0+f9mptkBxQqxYiA==","signatures":[{"sig":"MEYCIQD/4RfPlkD++S8DFwqzB/XEwmDbdYOVipQ87N/oSop7uwIhAOyvgpqOks+YIwD1pbWhAc3ndMFr8ib1KWOHv05DeJZz","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDJE/Uua4XjLVwqSk66OUvebWkObjQ0WUFTQg2FLdxvdAIhAKlXzs052ABGOj0m7jaiE6zQ3El7tatqykoQhVnUgwaC"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@charcuterie%2feslint-config@1.7.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":128130},"main":"./src/index.js","name":"@charcuterie/eslint-config","type":"module","exports":{".":"./src/index.js","./*":"./src/*"},"license":"MIT","scripts":{"test":"vitest","typecheck":"tsc --noEmit"},"version":"1.7.1","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7b77db8c-1558-47d7-8bcb-a587df645791"}},"homepage":"https://github.com/Sawtaytoes/charcuterie#readme","repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"_npmVersion":"11.19.0","description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","directories":{},"maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"_nodeVersion":"26.8.1","dependencies":{"typescript-eslint":"^8.59.2","eslint-plugin-react":"^7.37.5","@vitest/eslint-plugin":"^1.6.20"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^10.3.0","vitest":"^4.1.8","typescript":"^6.0.3","@types/node":"^25.6.2","typescript-eslint":"^8.59.2"},"peerDependencies":{"eslint":">=10"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/eslint-config_1.7.1_1788469141114_0.7034617100025848"}}},"time":{"created":"2026-07-31T04:31:05.613Z","modified":"2026-09-03T20:59:01.552Z","0.1.0":"2026-07-31T04:31:05.897Z","1.0.0":"2026-08-02T15:22:10.094Z","1.1.0":"2026-08-10T08:40:43.098Z","1.2.0":"2026-08-11T10:02:48.789Z","1.3.0":"2026-08-13T05:05:18.878Z","1.4.0":"2026-08-21T04:17:55.957Z","1.5.0":"2026-08-21T06:08:00.528Z","1.6.0":"2026-08-21T07:45:42.480Z","1.7.0":"2026-08-21T08:01:12.831Z","1.7.1":"2026-09-03T20:59:01.206Z"},"bugs":{"url":"https://github.com/Sawtaytoes/charcuterie/issues"},"license":"MIT","homepage":"https://github.com/Sawtaytoes/charcuterie#readme","repository":{"url":"git+https://github.com/Sawtaytoes/charcuterie.git","type":"git","directory":"packages/eslint-config"},"description":"The house ESLint rules Biome cannot express: type-aware naming, identifier length, and logical-properties-only.","maintainers":[{"name":"sawtaytoes","email":"saturn2888+npm@gmail.com"}],"readme":"# `@charcuterie/eslint-config`\n\nBiome does the formatting and most of the linting. This package holds only what\nBiome **cannot** express: rules needing TypeScript type information, and one custom\nAST query.\n\nExtracted from `mux-magic/eslint.config.js`, the reference app for every convention\nin this repo, so apps consume one import instead of six copy-pasted config files.\n\n## Installing\n\n```sh\nyarn add --dev @charcuterie/eslint-config eslint\n```\n\nTwo packages, and `eslint` is one of them only because the CLI belongs to the\nconsumer. `typescript-eslint`, `eslint-plugin-react` and `@vitest/eslint-plugin` are\nthis package's own dependencies — a shared config whose adoption instructions start\n\"first install these four plugins\" has not shared very much.\n\n**If your config composes `tseslint.configs.*` too, import it from here:**\n\n```js\nimport {\n  createAppConfig,\n  tseslint,\n} from \"@charcuterie/eslint-config\"\n```\n\nNot from your own `typescript-eslint`. Flat config throws\n`Cannot redefine plugin \"@typescript-eslint\"` when two blocks register that namespace\nwith two different objects, and a second copy of `typescript-eslint` in the tree is\nexactly that. `board-game-picker` adopted the preset with 8.66.0 pinned in its lockfile\nwhile this package resolved 8.67.0 beside it and `eslint .` failed outright; `docket`,\nwith the same declared range, deduped and worked. Which one a repo gets is a property of\nits lockfile, not of its config — so the instance is re-exported and there is one import\nspecifier for it.\n\n## Usage\n\n```js\n// eslint.config.js — the whole file, in an app repo\nimport { createAppConfig } from \"@charcuterie/eslint-config\"\nimport { defineConfig } from \"eslint/config\"\n\nexport default defineConfig(\n  ...createAppConfig({\n    tsconfigRootDir: import.meta.dirname,\n  }),\n)\n```\n\n`createAppConfig` is the default answer for an app. It composes the factories below\nin the right order, scoped off `@charcuterie/ui`, with the house ignore list already\nin place. Name where your source lives if it is not `src`:\n\n```js\ncreateAppConfig({\n  tsconfigRootDir: import.meta.dirname,\n  appDirectories: [\"packages/web\"],\n  // Repo-specific paths are *added* to `APP_IGNORES`, not\n  // swapped for it.\n  ignores: [\"e2e/**\"],\n})\n```\n\n| Option | Default | What it does |\n| --- | --- | --- |\n| `tsconfigRootDir` | **required** | Where the app's `tsconfig.json` lives. `projectService` has no honest default for somebody else's repo. |\n| `appDirectories` | `[\"src\"]` | The app's own source. This is the scoping that keeps the component rules off the library. |\n| `ignores` | `[]` | Appended to `APP_IGNORES`. |\n| `componentChoice` | `\"pickers\"` | `\"all\"` for all seven rules once the app has swept its raw anchors and buttons; `\"off\"` mid-migration. |\n| `flexOverflow` | `\"off\"` | `\"warn\"` or `\"error\"` to turn the flex family on. |\n| `reactVersion` | `\"19.0.0\"` | |\n| `storyFiles` | `MULTI_COMPONENT_FILE_GLOBS` | Files that may declare more than one component. |\n\n`react/no-multi-comp` is off for stories, `__fixtures__`, **`*.test.tsx`, and icon\nmodules** (`icons.tsx`, `*Icons.tsx`). The last two turned up the moment real apps ran the\npreset and are the same argument the story exemption already makes — the file's job is to\nhold a set. A component test that needs a wrapper declares the harness beside the\nassertion, and Charcuterie ships no icons on purpose, so every app has one file of glyphs:\n19 in `mail-sifter/components/icons.tsx`. Nineteen one-line files would be strictly worse,\nand nobody would write them — the rule would just get switched off.\n\n**Why the preset exists at all**, given that every factory below already takes\n`files`: because eight app repos each composed them by hand, and by 2026-08-21 six\nhad drifted. Four hand-registered the plugin object and the two picker rules by\nname — four copies of the same paragraph explaining why they were not calling\n`createComponentChoiceRules` next to it — and two never wired the block at all, so\nthe fleet's one machine-enforced picker rule was enforced in half the fleet. A rule\nthe library ships but every consumer has to re-derive is a rule the fleet does not\nhave.\n\n`componentChoice: \"pickers\"` is the default because it is the one component-choice\nfamily with a standing decision behind it and no remaining backlog: `Select` is\ndeprecated, `Picker` is the drop-in, and every owned app was swept onto `Listbox` on\n2026-08-21. The other five rules each name a sweep an app has not done —\n`no-raw-button` alone fires on every icon row in the fleet — and a config that turns\na whole repo red is a config that gets reverted rather than migrated.\n\n`flexOverflow` defaults to `\"off\"` for the same reason, one step further along:\n`no-shrink-0-with-flex-wrap` is an `error`, so bundling it would make \"adopt the\npreset\" and \"sweep the flex bugs\" the same change.\n\n### Composing by hand\n\nAn app with a layout the preset cannot describe still calls the factories directly —\nthe preset is built out of these, so there is no second implementation to keep in\nstep. `mux-magic` does this, because it layers its own `no-restricted-syntax`\nselectors onto the logical-properties ones.\n\n```js\n// eslint.config.js\nimport {\n  createComponentChoiceRules,\n  createFlexOverflowRules,\n  createLogicalPropertiesRules,\n  createPickerRules,\n  createReactRules,\n  createStoryOverrides,\n  createTestRules,\n  createTypedRules,\n} from \"@charcuterie/eslint-config\"\nimport { defineConfig } from \"eslint/config\"\n\nexport default defineConfig(\n  { ignores: [\"**/dist/**\", \"**/node_modules/**\"] },\n  createTypedRules({\n    tsconfigRootDir: import.meta.dirname,\n  }),\n  createReactRules({ files: [\"packages/ui/**/*.tsx\"] }),\n  createLogicalPropertiesRules({\n    files: [\"packages/ui/**/*.tsx\"],\n  }),\n  // The settled subset — `no-raw-select`,\n  // `prefer-listbox-over-select`, and the suppression guard.\n  createPickerRules({\n    files: [\"packages/web/**/*.tsx\"],\n  }),\n  // All seven. Opt-in, and pointed at app source rather than the\n  // library.\n  createComponentChoiceRules({\n    files: [\"packages/web/**/*.tsx\"],\n  }),\n  // Also opt-in. Warns by default; `severity: \"error\"` once the\n  // app has been swept.\n  createFlexOverflowRules({\n    files: [\"packages/web/**/*.tsx\"],\n  }),\n  createStoryOverrides({}),\n  createTestRules({}),\n)\n```\n\nEvery export is a **factory taking `files`** rather than a fixed config array. A\nshared config that hard-codes `packages/web/**` is a mux-magic config wearing a\nshared name; the consumer knows its own layout and this package does not.\n`createAppConfig` does not break that — it derives the globs from `appDirectories`\nrather than assuming them.\n\n`createTypedRules` needs `tsconfigRootDir` because it turns on `projectService` —\nthere is no honest default for where somebody else's tsconfig lives.\n\n## The rules\n\n| Rule | Why it is here and not in Biome |\n| --- | --- |\n| `@typescript-eslint/naming-convention` (is/has booleans) | keys off `types: [\"boolean\"]`, which needs the type checker |\n| `id-length` (min 2, `_` and `$` exempt) | Biome has no equivalent |\n| `react/no-multi-comp` | one component per file; off for stories and `__fixtures__` |\n| `vitest/consistent-test-it` (`test`, not `it`) | auto-fixable, which is the only reason a rule this cosmetic earns a slot |\n| `no-restricted-syntax` (logical properties only) | **new here** — see below |\n| `charcuterie/*` (component choice) | **opt-in**, except the picker subset — see below |\n| `charcuterie/*` (flex overflow) | **new here, and opt-in** — see below |\n\nAll the `charcuterie/*` rules live in **one plugin object under one namespace**, composed\nin `src/plugin.js`. Flat config throws `Cannot redefine plugin` when two blocks register\na namespace with two different objects, and the two blocks below are meant to be enabled\nindependently — so both factories hand ESLint the same reference. A second namespace\n(`charcuterie-layout`) was the alternative and was rejected: you would have to remember\nwhich prefix each rule takes when writing a disable comment, and a wrong prefix in an\n`eslint-disable` is silently a no-op.\n\n## Logical properties only\n\nEvery spatial value in this fleet is consumed logically — `ps-`/`pe-`, `ms-`/`me-`,\n`start-`/`end-`, `border-s`/`border-e`, `text-start`/`text-end`. It costs nothing\ntoday and makes RTL nearly free later, which is why it is a lint rule rather than a\npreference: a preference survives until the first person in a hurry.\n\n**Scope is deliberately narrow** — `className` string literals and template chunks\nonly. Physical property *names* in style objects (`left`, `paddingRight`) are not\nmatched, because `left` and `right` are legitimate identifiers in far too many\nplaces: `getBoundingClientRect().left`, Floating UI placements, gradient stops. A\nrule that cries wolf on those gets switched off, and a switched-off rule enforces\nnothing. Same reasoning that keeps the contrast gate scoped to control boundaries\nrather than every line on screen.\n\nThe pattern's anchors are load-bearing, and `__fixtures__/logicalDirectionClassName.tsx`\nexists to prove it: `border-red-500` contains `border-r`, `rounded-lg` contains\n`rounded-l`, `place-items-center` starts with `pl`. All three must stay clean.\n\n## Component choice — opt-in\n\nSix repos measured on 2026-08-10 keep reaching past the library for the same handful of\nraw elements. Documentation has been in place the whole time and moved none of these\nnumbers, which is the entire argument for a lint rule: a doc is read once, a rule is\nenforced on every save.\n\n| Rule | Fires on | Reach for instead | Measured in the fleet |\n| --- | --- | --- | --- |\n| `charcuterie/no-raw-anchor` | `<a>` | `TextLink`, or `ButtonLink` when navigation should look like a button | 14 in mux-magic, 10 in gallery-downloader, 31 in bambuddy |\n| `charcuterie/no-raw-button` | `<button>` | `Button`, or `IconButton` when the control is icon-only | every icon row in the fleet |\n| `charcuterie/no-raw-select` | `<select>` | `Listbox` (short, rich) or `Combobox` (long, searchable) | **134 in bambuddy**, 19 in spoolbuddy, 2 in points-market |\n| `charcuterie/prefer-listbox-over-select` | `<Select>` | `Picker` (the drop-in), `Listbox`, or `Combobox` — `Select` is **deprecated**, with no per-call-site exception left | [the 2026-08-20 deprecation](../../docs/decisions/2026-08-20-native-select-is-deprecated-and-the-platform-hatch-is-closed.md) |\n| `charcuterie/no-clickable-non-interactive` | `onClick` on `<div>`/`<span>`/`<li>`/… with no `role` or `tabIndex` | `Button`/`IconButton` to act, `TextLink`/`ButtonLink` to navigate | `points-market/…/AppShell.tsx:26-28` — a header title no keyboard can reach |\n| `charcuterie/no-navigation-in-click-handler` | `navigate()`, `router.push()`, `location.href =` inside an `onClick` | `TextLink`/`ButtonLink` with an `href` | all of plex-channels, and mail-sifter's whole shell |\n| `charcuterie/require-suppression-reason` | a disable of any rule above with no `-- reason` | say why in one line | — |\n\n`prefer-listbox-over-select` is the one rule whose escape hatch is **not** a call-site\njudgement: `Select` is deprecated, so a disable cites a decision record rather than a\nreason of its own. Everything already on a native `Select` is a conversion backlog —\n`Picker` takes the same `label` / `options` / `value` / `onChange`.\n\nBoth link components render a **real `<a href>`**, which is the point: middle-click,\nctrl-click, open-in-new-tab, copy-link and the browser's status-bar preview all work, and\nnone of them work on a click handler. Links go somewhere; buttons act on this page.\n\n`IconButton` gets its own rule for the same kind of reason — an icon-only `Button` has\nnothing but a glyph for its accessible name, so `IconButton` takes a required `label`.\n\n### Wiring it\n\n```js\ncreateComponentChoiceRules({\n  // The app's own source. `packages/ui/**` is deliberately not\n  // in here.\n  files: [\"packages/web/**/*.tsx\"],\n})\n```\n\nOr just the picker subset — `no-raw-select`, `prefer-listbox-over-select`, and the\nsuppression guard — which is what `createAppConfig` turns on by default and what\nfour repos were hand-registering before it existed:\n\n```js\ncreatePickerRules({ files: [\"packages/web/**/*.tsx\"] })\n```\n\nThe subset is not a compromise; it is the line between a settled decision and a\nbacklog. `Select` is deprecated with no per-call-site exception left and `Picker` is\na drop-in, so nothing in that pair is a judgement call. The other five each name a\nsweep — `no-raw-button` fires on every icon row in the fleet — which is why they stay\nbehind an explicit `componentChoice: \"all\"`.\n\nA repo that lints with Biome and not ESLint gets the same two mistakes caught by\n[`@charcuterie/biome-config/app`](../biome-config/README.md), which expresses them\nas `noRestrictedElements` and `noRestrictedImports`.\n\n**It is opt-in on purpose.** Five apps would go red the day they adopted it, and a config\nthat turns a whole repo red is a config that gets reverted rather than migrated — so it is\nits own block, added when an app is ready to fix what it finds.\n\n`files` is also the whole mechanism keeping the rules off `@charcuterie/ui`, which renders\nraw `<a>`, `<button>` and `<select>` because rendering them correctly *is* the library.\nPoint `files` at app source and the library never matches;\n`__fixtures__/uiPackage/rawElements.tsx` asserts it, because a scoping mechanism nobody\ntests is a scoping mechanism that silently stops scoping.\n\nThis block is **seven real plugin rules**, not `no-restricted-syntax` entries like the\nlogical-properties one — the plugin object is inline in this package, so there is still\nnothing extra to install, version or publish. Two things only distinct rule ids can do:\n\n1. **An escape hatch turns off exactly what it names.** A `no-restricted-syntax`\n   suppression is all-or-nothing, so silencing a raw `<a>` on one line would also silence\n   the logical-properties selectors on it.\n2. **Flat config replaces rule options rather than merging them.** Two blocks that both set\n   `no-restricted-syntax` over overlapping globs leave only the later one's selectors\n   running, silently.\n\n### The escape hatch\n\nEvery rule has one, and it has to carry a reason:\n\n```tsx\n// eslint-disable-next-line charcuterie/no-raw-select -- posted by the browser with no JS on the page at all\n<select name=\"theme\">…</select>\n```\n\n`charcuterie/require-suppression-reason` reports a disable of any of these rules that has no\n`-- reason` after it, including a blanket `// eslint-disable-next-line` (which silences them\ntoo). Other people's disable comments are left alone. Without the reason the rule stops\nfiring, nobody learns why the native element was the right call, and the next agent copies\nthe pattern — which is the failure this whole block exists to fix.\n\n## Flex overflow — opt-in\n\n**Four independent rediscoveries of one CSS rule in one day** (2026-08-11), during the\nfleet-wide bump onto `@charcuterie/ui@2.11.0`. The 17px type ramp consumed the slack that\nhad been hiding a latent layout bug in five of eleven repos, and four were the same\nshape: a flex row containing one long unbreakable token.\n\nA flex item's automatic minimum size resolves against its content's **min-content\nwidth**, so a token with no break opportunity becomes the row's floor and shoves its\nsibling out of the container. `min-width: 0` lets the *item* shrink but does nothing to\nthe *text*, which then spills; only `overflow-wrap: anywhere` shrinks the min-content\nsize itself.\n\n| Rule | Fires on | Default | Where it came from |\n| --- | --- | --- | --- |\n| `charcuterie/no-unconstrained-flex-text` | a text element (`span`, `h1`–`h6`, `p`, `label`, …) rendering `{dynamic}` text as a direct child of a flex **row**, with no escape in its `className` | **`warn`** | gallery-downloader `ErrorRow`, points-market `ShopPage` (heading + recent-buys chip) |\n| `charcuterie/no-shrink-0-with-flex-wrap` | `shrink-0` and `flex-wrap` on the same element, inside a flex row | **`error`** | rip-deck `RipCard` — and it found the identical bug uncaught in `HeldBayCard` and `QuarantinedBayCard` |\n\n**Any escape counts, because the four shipped fixes were four different fixes.**\n`min-w-0 wrap-anywhere` (gallery-downloader, points-market's heading), `flex-wrap` +\n`shrink-0` (points-market's price row), `truncate` + `title` (mail-sifter's host), and\n*removing* `shrink-0` (rip-deck). A rule demanding one of them would be wrong about the\nother three. Accepted: `min-w-*`, `truncate`, `text-ellipsis`, `line-clamp-*`,\n`overflow-hidden`, `wrap-anywhere`, `break-all`, `break-anywhere`, `w-*`, `max-w-*`,\n`basis-*`, `size-*`, `shrink-0`, `flex-none`, `absolute`, `fixed`.\n\n### Two severities, on purpose\n\n`no-unconstrained-flex-text` is a **heuristic**. It can see that a row's text child says\nnothing about how it shrinks; it cannot know whether `{status}` is `\"OK\"` or a\n300-character URL. Measured across the fleet it fires on 6/49 files in\ngallery-downloader, 5/11 in points-market, 8/12 in mail-sifter, 6/36 in rip-deck and\n33/341 in mux-magic — low volume, but a judgement call every time, so it **warns**. A\nrule that turns a repo red over a judgement call is a rule that gets deleted rather than\nsatisfied. Promote it once the app is swept:\n\n```js\ncreateFlexOverflowRules({\n  files: [\"packages/web/**/*.tsx\"],\n  severity: \"error\",\n})\n```\n\n`no-shrink-0-with-flex-wrap` is not a heuristic — `shrink-0` pins the item at\nmax-content, so the `flex-wrap` beside it can never engage — so it **errors**.\n\n### What it deliberately does not do\n\n- **`<div>` is not a text element.** It is the generic box and the most common child of a\n  flex row by a wide margin; including it turns the rule into a noise generator.\n- **Static text is skipped.** `Cancel` is never 300 characters. The bug arrives with\n  data, so only `{…}` children count — and not `{children}` or `{rows.map(…)}`, which\n  render somebody else's markup rather than a text run.\n- **`tabular-nums` is skipped.** It is the fleet's marker for a bounded digit run.\n  Without the exclusion the rule warns on rip-deck's three-character `{percentText}` even\n  *after* the shipped fix.\n- **A column container is out of scope**, and so is any container carrying a `flex-col`\n  variant: the shape is conditional and a conditional shape is not a confident finding.\n- **A `className` it cannot read statically** (a `clsx(…)` call, a variable) is skipped —\n  the escape may well be in there, and reporting on what it cannot read is the fastest\n  way to get switched off.\n- **`shrink-0` + `flex-wrap` needs a flex-row parent.** Inside a `flex-col`, `shrink-0`\n  resists shrinking down the *block* axis and has no bearing on the element's own wrap.\n  mux-magic's `FileExplorerModal` title bar is exactly that, and would have been the\n  rule's first false positive on the first real file it saw.\n\n**The one case it does not catch, stated plainly:** mail-sifter's `LinkCard` host. Its\noverflowing element is a block inside a grid column, not a flex item — the flex row above\nit was already correctly constrained — so no flex rule can see it. That one stays a\n`truncate` learned by reading.\n\nEscape hatch, same as everywhere else, and it owes a reason:\n\n```tsx\n{/* eslint-disable-next-line charcuterie/no-unconstrained-flex-text -- a closed enum, never longer than \"running\" */}\n<span className=\"text-xs uppercase\">{status}</span>\n```\n\n## Tests\n\n`src/houseRules.test.ts` runs the real `ESLint` class over `src/__fixtures__/`,\nfollowing `mux-magic/packages/tools/src/eslintBooleanPrefixRule.test.ts`. Asserting\nagainst the actual engine rather than a rule-tester harness catches the failure this\nrepo is most likely to hit — a rule configured correctly that never *applies*,\nbecause a `files` glob or a parser option is wrong. That silent no-op is\nindistinguishable from \"clean\" in CI.\n\n`src/__fixtures__/` has its own `tsconfig.json` so the type-aware rules can resolve\nit, and is excluded from the package's own typecheck — the fixtures are lint input,\nnot source.\n\n`__fixtures__/appPackage/unconstrainedFlexText.tsx` and its `constrained…` twin are the\nfour rows the fleet actually fixed on 2026-08-11, copied from the shipping commits\n(gallery-downloader `81e2c2a`, points-market `e6438b7`, mail-sifter `8ed11f4`, rip-deck\n`ce66aab`) — before and after. A lint rule whose motivating bug is not in its fixtures is\na rule nobody can show catches anything.\n","readmeFilename":"README.md"}