| 202 | } |
| 203 | |
| 204 | compare(a: Variant | null, z: Variant | null): number { |
| 205 | if (a === z) return 0 |
| 206 | if (a === null) return -1 |
| 207 | if (z === null) return 1 |
| 208 | |
| 209 | if (a.kind === 'arbitrary' && z.kind === 'arbitrary') { |
| 210 | // SAFETY: The selectors don't need to be checked for equality as they |
| 211 | // are guaranteed to be unique since we sort a list of de-duped variants |
| 212 | return a.selector < z.selector ? -1 : 1 |
| 213 | } else if (a.kind === 'arbitrary') { |
| 214 | return 1 |
| 215 | } else if (z.kind === 'arbitrary') { |
| 216 | return -1 |
| 217 | } |
| 218 | |
| 219 | let aOrder = this.variants.get(a.root)!.order |
| 220 | let zOrder = this.variants.get(z.root)!.order |
| 221 | |
| 222 | let orderedByVariant = aOrder - zOrder |
| 223 | if (orderedByVariant !== 0) return orderedByVariant |
| 224 | |
| 225 | if (a.kind === 'compound' && z.kind === 'compound') { |
| 226 | let order = this.compare(a.variant, z.variant) |
| 227 | if (order !== 0) return order |
| 228 | |
| 229 | if (a.modifier && z.modifier) { |
| 230 | // SAFETY: The modifiers don't need to be checked for equality as they |
| 231 | // are guaranteed to be unique since we sort a list of de-duped variants |
| 232 | return a.modifier.value < z.modifier.value ? -1 : 1 |
| 233 | } else if (a.modifier) { |
| 234 | return 1 |
| 235 | } else if (z.modifier) { |
| 236 | return -1 |
| 237 | } else { |
| 238 | return 0 |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | let compareFn = this.compareFns.get(aOrder) |
| 243 | if (compareFn !== undefined) return compareFn(a, z) |
| 244 | |
| 245 | if (a.root !== z.root) return a.root < z.root ? -1 : 1 |
| 246 | |
| 247 | // SAFETY: Variants `a` and `z` are both functional at this point. Static |
| 248 | // variants are de-duped by the `DefaultMap` and checked earlier. |
| 249 | let aValue = (a as Extract<Variant, { kind: 'functional' }>).value |
| 250 | let zValue = (z as Extract<Variant, { kind: 'functional' }>).value |
| 251 | |
| 252 | // While no functional variant in core supports a "default" value the parser |
| 253 | // will see something like `data:flex` and still parse and store it as a |
| 254 | // functional variant even though it actually produces no CSS. This means |
| 255 | // that we need to handle the case where the value is `null` here. Even |
| 256 | // though _for valid utilities_ this never happens. |
| 257 | if (aValue === null) return -1 |
| 258 | if (zValue === null) return 1 |
| 259 | |
| 260 | // Variants with arbitrary values should appear after any with named values |
| 261 | if (aValue.kind === 'arbitrary' && zValue.kind !== 'arbitrary') return 1 |