(subBlocks: SubBlockConfig[])
| 96 | * Build canonical group indices for a block's subblocks. |
| 97 | */ |
| 98 | export function buildCanonicalIndex(subBlocks: SubBlockConfig[]): CanonicalIndex { |
| 99 | const groupsById: Record<string, CanonicalGroup> = {} |
| 100 | const canonicalIdBySubBlockId: Record<string, string> = {} |
| 101 | |
| 102 | subBlocks.forEach((subBlock) => { |
| 103 | if (!subBlock.canonicalParamId) return |
| 104 | const canonicalId = subBlock.canonicalParamId |
| 105 | if (!groupsById[canonicalId]) { |
| 106 | groupsById[canonicalId] = { canonicalId, advancedIds: [] } |
| 107 | } |
| 108 | const group = groupsById[canonicalId] |
| 109 | if (subBlock.mode === 'advanced' || subBlock.mode === 'trigger-advanced') { |
| 110 | // Deduplicate: trigger spreads may repeat the same advanced ID as the regular block |
| 111 | if (!group.advancedIds.includes(subBlock.id)) { |
| 112 | group.advancedIds.push(subBlock.id) |
| 113 | } |
| 114 | } else { |
| 115 | // A trigger-mode subblock must not overwrite a basicId already claimed by a non-trigger subblock. |
| 116 | // Blocks spread their trigger's subBlocks after their own, so the regular subblock always wins. |
| 117 | if (!group.basicId || subBlock.mode !== 'trigger') { |
| 118 | group.basicId = subBlock.id |
| 119 | } |
| 120 | } |
| 121 | canonicalIdBySubBlockId[subBlock.id] = canonicalId |
| 122 | }) |
| 123 | |
| 124 | return { groupsById, canonicalIdBySubBlockId } |
| 125 | } |
| 126 | |
| 127 | /** |
| 128 | * Resolve if a canonical group is a swap pair (basic + advanced). |
no test coverage detected