You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Nice, focused addition. Implementation reuses State::is_styled, runs before minify/template_literals, and leans on CSS nesting to do the work. Snapshot + fixture pair is clear. A few things worth considering before merge:
Correctness / edge cases
1. is_bare_class_name accepts strings that don't form valid CSS class names (packages/styled-components/transform/src/lib.rs:95-99).
Allowing any string of [a-zA-Z0-9_-] is too permissive:
cssNamespace: \"123\" → .123 & (invalid — class selectors can't start with a digit).
cssNamespace: \"-\" or \"--\" → also invalid identifiers.
Empty after trim is already filtered, but a leading hyphen/digit slips through.
Consider rejecting (return None / log) or at least ensuring the first char is alpha/underscore. Alternatively, document that this branch is for "a single valid CSS identifier" and recommend users pass an explicit selector (.123) when in doubt.
2. No validation of arbitrary selector values — easy footgun.
cssNamespace is concatenated raw into every styled template (css_namespace.rs:38-39). A stray } or unterminated /* in the config silently corrupts every styled component in the project, with the broken CSS only visible at runtime. Since this is developer-supplied config, it's not a security issue, but a defensive check for balanced {}/comments (or just rejecting {, }, ;) would surface mistakes at build time rather than at render time.
3. wrap_template on the last quasis can collide with a trailing unterminated CSS comment.
If a styled template ends with /* trailing */ and no newline, appending } is fine. If it ends inside an unterminated block comment (already invalid CSS, but stylis tolerates some shapes), the } becomes part of the comment. Niche, but worth a comment in the visitor noting the assumption that input is well-formed CSS.
4. cooked = None is consistent with minify/visitor.rs:42-46 — good. Worth a one-line comment here mirroring the explanation there, so future readers know it's intentional rather than an oversight.
Test coverage gaps
No fixture for dynamic interpolation (styled.div\\\color: ${color};\``). This is the dominant real-world case; worth a fixture even though the wrap should be transparent to interpolations.
No fixture for **nested css\\\\`insidestyled\`\`**, which is a common shared-styles pattern. The current snapshot test asserts css` is not wrapped, but not that nested usage stays correct.
No fixture for **styled.div.attrs(...)\\\\`/withConfigchains** —State::is_styled` handles these via recursion, but a regression fixture would lock that in.
No fixture for the invalid/edge config values discussed above (empty string is implicitly covered by the early return; whitespace-only, leading digit, etc. are not).
Minor
CssNamespace.state is only used inside visit_mut_expr for the is_styled check — fine, just noting that this visitor walks every Expr in the program, same as minify/template_literals. Performance parity is acceptable.
README example is good. Consider explicitly calling out that object styles are not namespaced (the fixture verifies this but the docs only mention css/keyframes/createGlobalStyle). Users with mixed object + template usage will be surprised otherwise.
Snapshot uses the JS output post-template_literals transpile, so the CSS that ships to stylis is the raw inside the array. Worth a quick manual check that .myapp &{...} survives styled-components' own preprocessing in a real app — the unit tests don't exercise that path.
Ordering note
css_namespace runs aftertranspile_css_prop, which means css={...} props are also namespaced. That's probably what users want, but it's an undocumented side-effect — worth either confirming intentionally or mentioning in the README.
Overall: solid PR, the wrapper-via-nesting approach is clean. The main asks are config validation and a couple of additional fixtures.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
cssNamespaceoption to@swc/plugin-styled-componentsso styled template CSS can be scoped under a parent selector, addressing #616.Changes
cssNamespaceconfig parsing and selector normalization.css,keyframes, andcreateGlobalStyleun-namespaced.Validation
cargo test -p styled_componentscargo test -p styled_components --test fixture -- --include-ignored css_namespacecargo test -p styled_components --test fixture -- --include-ignored --skip transformed_imports_with_jsx_member_expressionspnpm -F @swc/plugin-styled-components run testgit diff --check