{"record":{"id":"a1e3f4a2169e21ed","repo":"amruthpillai/reactive-resume","slug":"selector-uses-an-unknown-role","errorCode":null,"errorMessage":"Selector uses an unknown role.","messagePattern":"Selector uses an unknown role\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/resume/src/stylesheet/selector.ts","lineNumber":131,"sourceCode":"\t}\n\n\treturn [...roles].some((role) => matchesAttribute(role, matcher, value));\n}\n\nfunction validateCompound(selectors: readonly CompiledSimpleSelector[]): void {\n\tconst types = selectors.filter(\n\t\t(selector): selector is Extract<CompiledSimpleSelector, { type: \"type\" }> => selector.type === \"type\",\n\t);\n\tif (types.length > 1) throw new Error(\"A compound selector can contain only one type selector.\");\n\n\tconst type = types[0]?.name ?? null;\n\tfor (const selector of selectors) {\n\t\tif (selector.type !== \"attribute\") continue;\n\n\t\tif (selector.name === \"id\") continue;\n\t\tif (selector.name === \"role\") {\n\t\t\tif (!roleValueIsKnown(selector.matcher, selector.value, allowedRoles(type))) {\n\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.`);","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/amruthpillai/reactive-resume/blob/3a5b12e2a40374a9571988701fcb75c5a1831c42/packages/resume/src/stylesheet/selector.ts#L113-L149","documentation":"Thrown by validateCompound when an attribute selector targeting [role] references a role value that is not registered for the compound's semantic element type (or for any type when the compound has no type selector). The SEMANTIC_REGISTRY_V1 map enumerates the only legal role tokens per kind; :nth-child-style whitespace token lists and ~= single tokens must all be members of that set.","triggerScenarios":"Authoring [role~=\"fake-role\"], item[role=\"experience-role nonexistent\"], or any [role|=...]/[^=...]/[$=...]/[*=...] whose pattern matches zero roles registered for the targeted kind (e.g. region[role~=\"primary-text\"] where region declares no roles).","commonSituations":"Copying ARIA role names from HTML/DOM mental models into resume semantic CSS; guessing role names without consulting the registry; pairing a role that exists on 'field' with a different element like 'section'.","solutions":["Look up the allowed roles for your element kind in SEMANTIC_REGISTRY_V1[kind].roles and use one of those exact tokens.","If you do not know the type, restrict yourself to roles that appear in any definition (the union exported via the registry).","Drop the [role=...] clause and target the element by kind or id instead.","For ~= matcher, pass a single token; for = matcher, ensure every whitespace-separated token is a registered role."],"exampleFix":"// before\nitem[role~=\"team-lead\"]\n// after\nitem[role~=\"experience-role\"]","handlingStrategy":"validation","validationCode":"import { SEMANTIC_REGISTRY_V1 } from '@reactive-resume/resume';\n\nconst roleIsKnown = (type, matcher, value) => {\n  const roles = type\n    ? new Set(SEMANTIC_REGISTRY_V1[type].roles)\n    : new Set(Object.values(SEMANTIC_REGISTRY_V1).flatMap(d => d.roles));\n  if (!matcher || value === null) return roles.size > 0;\n  if (matcher === '~=') return roles.has(value);\n  if (matcher === '=') return value.split(/\\s+/).filter(Boolean).every(t => roles.has(t));\n  return [...roles].some(r =>\n    matcher === '|=' ? r === value || r.startsWith(value + '-')\n    : matcher === '^=' ? r.startsWith(value)\n    : matcher === '$=' ? r.endsWith(value)\n    : matcher === '*=' ? r.includes(value)\n    : false);\n};\n// call before building [role=...] selectors","typeGuard":"import type { CompileSelectorResult } from '@reactive-resume/resume';\n\nconst isRejected = (r: CompileSelectorResult): r is CompileSelectorResult & { selector: null; error: string } =>\n  r.selector === null && typeof r.error === 'string';","tryCatchPattern":"const result = compileSelector(selector);\nif (result.selector === null) {\n  // result.error === 'Selector uses an unknown role.'\n  reportToSelectorAuthor(result.error, selector);\n}","preventionTips":["Source role tokens from SEMANTIC_REGISTRY_V1[kind].roles rather than guessing.","Treat the registry as the single source of truth and lint selectors against it at authoring time.","Remember ARIA role names from HTML do not carry over to this semantic model."],"tags":["semantic-css","selector","role","validation"],"backgroundTag":null,"analyzedSha":"3a5b12e2a40374a9571988701fcb75c5a1831c42","analyzedAt":"2026-08-12T22:31:22.666Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}