(decl)
| 2385 | * @param {Declaration} decl the `composes` declaration |
| 2386 | */ |
| 2387 | const emitComposesWithAnchor = (decl) => { |
| 2388 | if (currentRule.localIdentifiers.length > 1) { |
| 2389 | this._emitWarning( |
| 2390 | state, |
| 2391 | `Composition is only allowed when selector is single local class name not in "${currentRule.localIdentifiers.join( |
| 2392 | '", "' |
| 2393 | )}"`, |
| 2394 | locConverter, |
| 2395 | A.start(decl), |
| 2396 | A.end(decl) |
| 2397 | ); |
| 2398 | return; |
| 2399 | } |
| 2400 | const lastLocalIdentifier = currentRule.localIdentifiers[0]; |
| 2401 | |
| 2402 | // Split the value at top-level commas — each segment is one `<name>+ [from <source>]` group. |
| 2403 | /** @type {AstNode[][]} */ |
| 2404 | const groups = []; |
| 2405 | /** @type {AstNode[]} */ |
| 2406 | let currentGroup = []; |
| 2407 | for (const cv of A.children(decl)) { |
| 2408 | if (A.type(cv) === NodeType.Comma) { |
| 2409 | groups.push(currentGroup); |
| 2410 | currentGroup = []; |
| 2411 | } else { |
| 2412 | currentGroup.push(cv); |
| 2413 | } |
| 2414 | } |
| 2415 | groups.push(currentGroup); |
| 2416 | |
| 2417 | // Inline scan + dispatch per group — warm path (composes-heavy modules), so no per-group result object is allocated. |
| 2418 | for (const group of groups) { |
| 2419 | /** @type {{ start: number, end: number, isGlobal: boolean }[]} */ |
| 2420 | const classNames = []; |
| 2421 | /** @type {"names" | "expecting-source" | "done"} */ |
| 2422 | let phase = "names"; |
| 2423 | /** @type {{ kind: "string", path: string } | { kind: "global" } | undefined} */ |
| 2424 | let fromSource; |
| 2425 | /** @type {AstNode | undefined} */ |
| 2426 | let errorToken; |
| 2427 | let errorMessage = ""; |
| 2428 | |
| 2429 | for (let i = 0; i < group.length; i++) { |
| 2430 | const cv = group[i]; |
| 2431 | if (A.type(cv) === NodeType.Whitespace) continue; |
| 2432 | |
| 2433 | if (phase === "expecting-source") { |
| 2434 | if (A.type(cv) === NodeType.String) { |
| 2435 | fromSource = { |
| 2436 | kind: "string", |
| 2437 | path: source.slice(A.start(cv) + 1, A.end(cv) - 1) |
| 2438 | }; |
| 2439 | phase = "done"; |
| 2440 | continue; |
| 2441 | } |
| 2442 | if ( |
| 2443 | A.type(cv) === NodeType.Ident && |
| 2444 | equalsLowerCase(A.value(cv), "global") |
nothing calls this directly
no test coverage detected