{"record":{"id":"c6da7018e3c77dc9","repo":"swc-project/swc","slug":"expected-extension-name-should-start-with","errorCode":null,"errorMessage":"Expected Extension name should start with '--'","messagePattern":"Expected Extension name should start with '--'","errorType":"validation","errorClass":"swc_css_parser::error::Error","httpStatus":null,"severity":"error","filePath":"crates/swc_css_parser/src/parser/at_rules/mod.rs","lineNumber":2548,"sourceCode":"{\n    fn parse(&mut self) -> PResult<ExtensionName> {\n        let span = self.input.cur_span();\n\n        if !is!(self, Ident) {\n            return Err(Error::new(span, ErrorKind::Expected(\"indent token\")));\n        }\n\n        // All extensions defined in this specification use a common syntax for defining\n        // their ”names”: the <extension-name> production. An <extension-name> is any\n        // identifier that starts with two dashes (U+002D HYPHEN-MINUS), like --foo, or\n        // even exotic names like -- or ------. The CSS language will never use\n        // identifiers of this form for any language-defined purpose, so it’s safe to\n        // use them for author-defined purposes without ever having to worry about\n        // colliding with CSS-defined names.\n        match bump!(self) {\n            Token::Ident { value, raw, .. } => {\n                if !value.starts_with(\"--\") {\n                    return Err(Error::new(\n                        span,\n                        ErrorKind::Expected(\"Extension name should start with '--'\"),\n                    ));\n                }\n\n                Ok(ExtensionName {\n                    span,\n                    value,\n                    raw: Some(raw),\n                })\n            }\n            _ => {\n                unreachable!()\n            }\n        }\n    }\n}\n","sourceCodeStart":2530,"sourceCodeEnd":2566,"githubUrl":"https://github.com/swc-project/swc/blob/5176682b65416c6b5de6b47379ae1588ea3ecb3f/crates/swc_css_parser/src/parser/at_rules/mod.rs#L2530-L2566","documentation":"The CSS specification reserves identifiers beginning with two dashes (U+002D) for author-defined extensions; <extension-name> is defined to be exactly such an identifier ('--foo', even '--' or '------'). The parser consumed an identifier token, but it does not start with '--', so it cannot serve as an extension name in @custom-media (and similar extension grammars).","triggerScenarios":"'@custom-media wide (min-width: 100px);' — a plain identifier without the double-dash prefix; also names like '-wide' (single dash) or '_wide'.","commonSituations":"Authors treating @custom-media like Sass variables and omitting the dashes; migrating from preprocessor variable naming into native CSS custom media; single dash typed instead of two.","solutions":["Prefix the name with '--': '@custom-media --wide (min-width: 100px);'","Use exactly two leading dashes — a single dash ('-wide') still fails","Lint custom media names with /^--/ before parsing"],"exampleFix":"/* before */\n@custom-media wide (min-width: 100px);\n/* after */\n@custom-media --wide (min-width: 100px);","handlingStrategy":"type-guard","validationCode":"function hasDoubleDashPrefix(name) { return name.startsWith('--'); }","typeGuard":"// Rust\nfn is_valid_extension_name(s: &str) -> bool { s.starts_with(\"--\") }","tryCatchPattern":"// Rust: normalize before parse instead of catching after\nlet name = if !is_valid_extension_name(&name) { format!(\"--{name}\") } else { name };","preventionTips":["Enforce /^--/ with a lint rule (stylelint custom-media-pattern)","Treat '--' as the reserved namespace for author-defined names in generators"],"tags":["css","custom-media","naming","syntax"],"backgroundTag":"css-custom-ident-naming","analyzedSha":"5176682b65416c6b5de6b47379ae1588ea3ecb3f","analyzedAt":"2026-08-17T16:16:52.067Z","contentChangedAt":"2026-08-17T16:16:52.067Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}