{"record":{"id":"c67ffcc746b149fa","repo":"dianping/cat","slug":"unknown-rule","errorCode":null,"errorMessage":"Unknown @ rule.","messagePattern":"Unknown @ rule\\.","errorType":"exception","errorClass":"SyntaxError","httpStatus":null,"severity":"error","filePath":"cat-home/src/main/webapp/assets/js/editor/worker-css.js","lineNumber":2049,"sourceCode":"                                    this.fire({\n                                        type:       \"error\",\n                                        error:      null,\n                                        message:    \"Unknown @ rule: \" + tokenStream.LT(0).value + \".\",\n                                        line:       tokenStream.LT(0).startLine,\n                                        col:        tokenStream.LT(0).startCol\n                                    });\n                                    count=0;\n                                    while (tokenStream.advance([Tokens.LBRACE, Tokens.RBRACE]) == Tokens.LBRACE){\n                                        count++;    //keep track of nesting depth\n                                    }\n\n                                    while(count){\n                                        tokenStream.advance([Tokens.RBRACE]);\n                                        count--;\n                                    }\n\n                                } else {\n                                    throw new SyntaxError(\"Unknown @ rule.\", tokenStream.LT(0).startLine, tokenStream.LT(0).startCol);\n                                }\n                                break;\n                            case Tokens.S:\n                                this._readWhitespace();\n                                break;\n                            default:\n                                if(!this._ruleset()){\n                                    switch(tt){\n                                        case Tokens.CHARSET_SYM:\n                                            token = tokenStream.LT(1);\n                                            this._charset(false);\n                                            throw new SyntaxError(\"@charset not allowed here.\", token.startLine, token.startCol);\n                                        case Tokens.IMPORT_SYM:\n                                            token = tokenStream.LT(1);\n                                            this._import(false);\n                                            throw new SyntaxError(\"@import not allowed here.\", token.startLine, token.startCol);\n                                        case Tokens.NAMESPACE_SYM:\n                                            token = tokenStream.LT(1);","sourceCodeStart":2031,"sourceCodeEnd":2067,"githubUrl":"https://github.com/dianping/cat/blob/e815e74d4c2dd74edac831241f1253fcc7d25381/cat-home/src/main/webapp/assets/js/editor/worker-css.js#L2031-L2067","documentation":"Thrown by the CSS worker's stylesheet parser when it encounters an `@` token whose at-keyword is not one of the at-rules it implements (`@media`, `@page`, `@import`, `@charset`, `@namespace`, `@font-face`, `@keyframes`/vendor variants, `@supports`-era rules absent here). After the recognized cases fall through, the else branch throws `SyntaxError('Unknown @ rule.')` anchored at the at-token's position. It is a grammar-coverage failure: the CSS is (or may be) valid, but this parser build does not know the rule.","triggerScenarios":"Stylesheets using at-rules newer or less common than the parser's set: `@supports`, `@document`, `@viewport`, `@counter-style`, `@font-feature-values`, `@layer`, `@container`, `@scope`; or a typo'd at-rule like `@medi (min-width:0)`. Parsing such input through this worker's `parse()`/`_stylesheet()` path.","commonSituations":"Modern CSS shipped to an older bundled worker-css.js (common in long-lived apps and CMS installs); CSS written for a preprocessor (`@extend`, `@mixin` from Sass) accidentally fed to the plain CSS parser; vendor-specific at-rules the token table lacks.","solutions":["Identify the at-rule at the reported position; if it was a typo (e.g. `@medi`), correct it to a real at-rule.","If the rule is modern-but-valid (`@supports`, `@layer`, `@container`), move it into a file this parser does not validate, or upgrade/replace worker-css.js with a parser that supports it (postcss, css-tree).","Strip preprocessor directives (`@mixin`, `@extend`) before handing compiled output to the worker — feed the compiled CSS, not the Sass source.","Run in non-strict mode and subscribe to the parser's 'error' event so unknown at-rules are reported per-rule instead of aborting the whole parse."],"exampleFix":"/* before */\n@supports (display: grid) { .g { display: grid; } } /* parser: Unknown @ rule. */\n\n/* after (option 1: rule this parser knows) */\n@media (min-width: 0) { .g { display: block; } }\n/* after (option 2): keep @supports and upgrade/swap the CSS parser */","handlingStrategy":"try-catch","validationCode":"var KNOWN_AT = /^@(media|page|import|charset|namespace|font-face|(-moz|-o|-webkit|-ms-)?keyframes)\\b/;\nfunction preflightAtRules(css) {\n  var unknown = [];\n  (css.match(/@[\\w-]+/g) || []).forEach(function (r) {\n    if (!KNOWN_AT.test(r)) unknown.push(r);\n  });\n  return unknown; // e.g. ['@supports', '@layer'] -> route around this parser\n}","typeGuard":null,"tryCatchPattern":"try {\n  parser.parse(css);\n} catch (ex) {\n  if (/Unknown @ rule/.test(ex.message)) { logWarn('skipping modern at-rule at ' + ex.line + ':' + ex.col); return; }\n  throw ex;\n}","preventionTips":["Scan for at-rules your parser build knows before validating modern CSS.","Keep worker-css.js updated or move linting to a maintained parser (stylelint/postcss) for modern CSS.","Feed compiled CSS (never Sass/Less directives) to the plain CSS worker.","Run non-strict so unknown at-rules become reported events, not fatal throws."],"tags":["css","parser","at-rule","syntax-error","unsupported-feature"],"backgroundTag":null,"analyzedSha":"e815e74d4c2dd74edac831241f1253fcc7d25381","analyzedAt":"2026-08-14T14:22:34.512Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}