From a33043280f0f3fb6f5d3eaac0441480162a2899a Mon Sep 17 00:00:00 2001 From: Brian Love Date: Sat, 29 Aug 2026 16:24:06 -0700 Subject: [PATCH] chore(website): lint guard against new static inline styles Lands only now that all seven migration batches (#848-#857) are merged, so it never sees legacy code. Flags identifier-keyed members of a style object literal in apps/website/src; the style={{ '--x': value }} escape hatch uses string-literal keys and passes. Excluded: the two Satori OG-image files (inline-only by design - note the [slug] segment must be matched by wildcard, brackets are a glob character class), the dev-only primitives route, and specs. Verified with raw eslint: fires on an identifier-key probe, silent on a custom-property probe, zero hits on the OG file. Baseline is 18 warnings - exactly the documented dynamic-value sites from the batch reports - and 0 errors, so CI (which fails on errors only) stays green. Ships as 'warn'; the escalation to 'error' is a deliberate follow-up one release later. Co-Authored-By: Claude Opus 5 --- eslint.config.mjs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/eslint.config.mjs b/eslint.config.mjs index ef41ef068..1f12b0dd9 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -54,4 +54,34 @@ export default [ // Override or add rules here rules: {}, }, + // Inline-style guard — apps/website migrated off static inline styles + // (docs/superpowers/specs/2026-08-29-inline-style-substrate-migration-design.md, + // batches #848–#857). Flags identifier-keyed members of a style object + // literal. The escape hatch for dynamic values — style={{ '--x': value }} — + // uses string-literal keys and passes. Genuinely dynamic identifier-keyed + // values (rare) get a targeted eslint-disable-next-line with a reason. + // Ships as 'warn' for one release, then 'error'. + { + files: ['apps/website/src/**/*.tsx'], + ignores: [ + // Satori-rendered OG images: inline styles are the only mechanism there. + 'apps/website/src/app/opengraph-image.tsx', + // NOTE: [slug] would be a glob character class, so match by wildcard. + 'apps/website/src/app/blog/*/opengraph-image.tsx', + // Dev-only route slated for deletion. + 'apps/website/src/app/dev/primitives/page.tsx', + 'apps/website/src/**/*.spec.tsx', + ], + rules: { + 'no-restricted-syntax': [ + 'warn', + { + selector: + 'JSXAttribute[name.name="style"] > JSXExpressionContainer > ObjectExpression > Property[key.type="Identifier"]', + message: + "Static presentation belongs in src/styles/*.css (see the substrate-migration spec). For dynamic values, set a CSS custom property: style={{ '--x': value }}.", + }, + ], + }, + }, ];