{"record":{"id":"e780d908e171de39","repo":"amruthpillai/reactive-resume","slug":"attribute-selector-matcher-and-value-must-be-used","errorCode":null,"errorMessage":"Attribute selector matcher and value must be used together.","messagePattern":"Attribute selector matcher and value must be used together\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/resume/src/stylesheet/selector.ts","lineNumber":198,"sourceCode":"\t\tcase \"TypeSelector\": {\n\t\t\tconst name = astName(node);\n\t\t\tif (name === \"*\") return { type: \"universal\" };\n\t\t\tif (!knownKinds.has(name)) throw new Error(`Unknown semantic element ${name}.`);\n\t\t\treturn { type: \"type\", name: name as SemanticNode[\"kind\"] };\n\t\t}\n\t\tcase \"IdSelector\":\n\t\t\treturn { type: \"id\", value: astName(node) };\n\t\tcase \"AttributeSelector\": {\n\t\t\tconst name = astName(node);\n\t\t\tif (!knownAttributes.has(name)) throw new Error(`Unknown semantic attribute ${name}.`);\n\t\t\tif (node.flags) throw new Error(\"Attribute selector flags are not supported.\");\n\t\t\tconst matcher = node.matcher as AttributeMatcher | null | undefined;\n\t\t\tif (matcher !== null && matcher !== undefined && ![\"=\", \"~=\", \"|=\", \"^=\", \"$=\", \"*=\"].includes(matcher)) {\n\t\t\t\tthrow new Error(`Unsupported attribute matcher ${matcher}.`);\n\t\t\t}\n\t\t\tconst value = attributeValue(node);\n\t\t\tif ((matcher === null || matcher === undefined) !== (value === null)) {\n\t\t\t\tthrow new Error(\"Attribute selector matcher and value must be used together.\");\n\t\t\t}\n\t\t\treturn { type: \"attribute\", name, matcher: matcher ?? null, value };\n\t\t}\n\t\tcase \"PseudoClassSelector\": {\n\t\t\tconst name = astName(node);\n\t\t\tif ([\"root\", \"first-child\", \"last-child\", \"only-child\"].includes(name)) {\n\t\t\t\tif (node.children !== null && node.children !== undefined)\n\t\t\t\t\tthrow new Error(`:${name} does not accept arguments.`);\n\t\t\t\treturn { type: \"pseudo\", name: name as \"root\" | \"first-child\" | \"last-child\" | \"only-child\" };\n\t\t\t}\n\t\t\tif ([\"is\", \"where\", \"not\"].includes(name)) {\n\t\t\t\tif (context.depth >= SEMANTIC_CSS_LIMITS_V1.maxFunctionDepth) {\n\t\t\t\t\tthrow new Error(\"Selector function nesting is too deep.\");\n\t\t\t\t}\n\t\t\t\tconst nested = childrenOf(node);\n\t\t\t\tif (nested.length !== 1 || nested[0]?.type !== \"SelectorList\") {\n\t\t\t\t\tthrow new Error(`:${name} requires a selector list.`);\n\t\t\t\t}","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/amruthpillai/reactive-resume/blob/3a5b12e2a40374a9571988701fcb75c5a1831c42/packages/resume/src/stylesheet/selector.ts#L180-L216","documentation":"Thrown by compileSimple in the AttributeSelector branch when a matcher and a value are not both present or both absent (the XOR of 'matcher is null/undefined' and 'value is null' is true). A bare [attr=val] needs both; a presence [attr] needs neither.","triggerScenarios":"A programmatically built AST with a matcher but no value, or a value but no matcher; malformed selector fragments produced by string concatenation.","commonSituations":"Templating selector strings and forgetting the value; constructing CssNode objects manually; partial regex substitutions on selectors.","solutions":["For a value comparison, include both: [type='experience'].","For presence only, include neither: [type].","Validate the (matcher, value) pairing before interpolating into a selector string."],"exampleFix":"// before\n// AST: { name:'type', matcher:'=', value:null }\n// after\n[type='experience']","handlingStrategy":"validation","validationCode":"const matcherAndValuePaired = (matcher, value) =>\n  (matcher === null || matcher === undefined) === (value === null);\n// verify before constructing an AttributeSelector node","typeGuard":"const isRejected = (r) => r.selector === null && typeof r.error === 'string';","tryCatchPattern":"const result = compileSelector(selectorOrAst);\nif (result.selector === null && result.error === 'Attribute selector matcher and value must be used together.') {\n  addMissingValueOrMatcher();\n}","preventionTips":["Always pair a matcher with a value, or omit both for a presence test.","Validate templated selector fragments for half-built attribute selectors.","Prefer authoring selectors as strings over building AST by hand."],"tags":["semantic-css","selector","attribute","matcher","ast"],"backgroundTag":null,"analyzedSha":"3a5b12e2a40374a9571988701fcb75c5a1831c42","analyzedAt":"2026-08-12T22:31:22.666Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}