{"record":{"id":"52f37cea03426d73","repo":"amruthpillai/reactive-resume","slug":"name-requires-one-an-b-expression","errorCode":null,"errorMessage":":${name} requires one An+B expression.","messagePattern":":(.+?) requires one An\\+B expression\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/resume/src/stylesheet/selector.ts","lineNumber":149,"sourceCode":"\t\t\t\tthrow new Error(\"Selector uses an unknown role.\");\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (type && !(SEMANTIC_REGISTRY_V1[type].attributes as readonly string[]).includes(selector.name)) {\n\t\t\tthrow new Error(`Attribute ${selector.name} is not available on ${type}.`);\n\t\t}\n\t}\n}\n\nfunction compileNth(\n\tnode: SelectorAst,\n\tname: \"nth-child\" | \"nth-of-type\",\n\tcontext: CompileContext,\n): CompiledSimpleSelector {\n\tconst nth = childrenOf(node);\n\tif (nth.length !== 1 || nth[0]?.type !== \"Nth\" || !nth[0].nth) {\n\t\tthrow new Error(`:${name} requires one An+B expression.`);\n\t}\n\n\tconst expression = nth[0].nth;\n\tlet a = 0;\n\tlet b = 0;\n\tif (expression.type === \"Identifier\") {\n\t\tconst keyword = astName(expression).toLowerCase();\n\t\tif (keyword === \"odd\") {\n\t\t\ta = 2;\n\t\t\tb = 1;\n\t\t} else if (keyword === \"even\") {\n\t\t\ta = 2;\n\t\t} else {\n\t\t\tthrow new Error(`Unsupported :${name} expression.`);\n\t\t}\n\t} else if (expression.type === \"AnPlusB\") {\n\t\ta = expression.a === null || expression.a === undefined ? 0 : Number(expression.a);\n\t\tb = expression.b === null || expression.b === undefined ? 0 : Number(expression.b);","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/amruthpillai/reactive-resume/blob/3a5b12e2a40374a9571988701fcb75c5a1831c42/packages/resume/src/stylesheet/selector.ts#L131-L167","documentation":"Thrown by compileNth when a :nth-child or :nth-of-type pseudo-class does not contain exactly one Nth AST node with a parsed nth expression. css-tree normally produces this shape for valid An+B syntax; anything else (empty argument list, wrong node type) is rejected.","triggerScenarios":"Writing :nth-child() with empty parentheses, :nth-child(,) with a stray comma, or a malformed argument that css-tree parsed into something other than a single Nth node.","commonSituations":"Hand-typing nth expressions; dynamically templating selector strings with an empty/undefined step value; copy-pasting partial CSS.","solutions":["Provide exactly one An+B expression: :nth-child(2), :nth-child(2n+1), :nth-child(odd), or :nth-child(even).","If the step comes from a variable, guard it is non-empty before interpolating.","Run the selector through compileSelector and read result.error to catch malformed nth at authoring time."],"exampleFix":"// before\nitem:nth-child()\n// after\nitem:nth-child(2)","handlingStrategy":"validation","validationCode":"import { compileSelector } from '@reactive-resume/resume';\n\nconst nthIsValid = (selector) => compileSelector(selector).selector !== null;\n// rejects :nth-child() / :nth-of-type() with no valid An+B node","typeGuard":"const isRejected = (r) => r.selector === null && typeof r.error === 'string';","tryCatchPattern":"const result = compileSelector('item:nth-child()');\nif (result.selector === null) {\n  // result.error === ':nth-child requires one An+B expression.'\n  promptUserForNthExpression();\n}","preventionTips":["Always provide a concrete An+B argument inside nth pseudo-classes.","Guard dynamic nth values for emptiness before interpolating.","Prefer odd/even/integer forms for readability."],"tags":["semantic-css","selector","nth","pseudo-class"],"backgroundTag":null,"analyzedSha":"3a5b12e2a40374a9571988701fcb75c5a1831c42","analyzedAt":"2026-08-12T22:31:22.666Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}