@@ -23,7 +23,9 @@ import { remapBitfield } from './remap-bitfield.js'
2323 * @property {bigint } arbitrary 0n if false, 1n if true
2424 * @property {bigint } variants Dynamic size. 1 bit per registered variant. 0n means no variants
2525 * @property {bigint } parallelIndex Rule index for the parallel variant. 0 if not applicable.
26- * @property {bigint } index Index of the rule / utility in it's given *parent* layer. Monotonically increasing.
26+ * @property {bigint } index Index of the rule / utility in its given *parent* layer. Monotonically increasing.
27+ * @property {bigint } propertyOffset Offset for the arbitrary property. Only valid after sorting.
28+ * @property {string } property Name/Value of the arbitrary property.
2729 * @property {VariantOption[] } options Some information on how we can sort arbitrary variants
2830 */
2931
@@ -88,17 +90,21 @@ export class Offsets {
8890 variants : 0n ,
8991 parallelIndex : 0n ,
9092 index : this . offsets [ layer ] ++ ,
93+ propertyOffset : 0n ,
94+ property : '' ,
9195 options : [ ] ,
9296 }
9397 }
9498
9599 /**
100+ * @param {string } name
96101 * @returns {RuleOffset }
97102 */
98- arbitraryProperty ( ) {
103+ arbitraryProperty ( name ) {
99104 return {
100105 ...this . create ( 'utilities' ) ,
101106 arbitrary : 1n ,
107+ property : name ,
102108 }
103109 }
104110
@@ -262,6 +268,11 @@ export class Offsets {
262268 return a . arbitrary - b . arbitrary
263269 }
264270
271+ // Always sort arbitrary properties alphabetically
272+ if ( a . propertyOffset !== b . propertyOffset ) {
273+ return a . propertyOffset - b . propertyOffset
274+ }
275+
265276 // Sort utilities, components, etc… in the order they were registered
266277 return a . index - b . index
267278 }
@@ -320,14 +331,62 @@ export class Offsets {
320331 } )
321332 }
322333
334+ /**
335+ * @template T
336+ * @param {[RuleOffset, T][] } list
337+ * @returns {[RuleOffset, T][] }
338+ */
339+ sortArbitraryProperties ( list ) {
340+ // Collect all known arbitrary properties
341+ let known = new Set ( )
342+
343+ for ( let [ offset ] of list ) {
344+ if ( offset . arbitrary === 1n ) {
345+ known . add ( offset . property )
346+ }
347+ }
348+
349+ // No arbitrary properties? Nothing to do.
350+ if ( known . size === 0 ) {
351+ return list
352+ }
353+
354+ // Sort the properties alphabetically
355+ let properties = Array . from ( known ) . sort ( )
356+
357+ // Create a map from the property name to its offset
358+ let offsets = new Map ( )
359+
360+ let offset = 1n
361+ for ( let property of properties ) {
362+ offsets . set ( property , offset ++ )
363+ }
364+
365+ // Apply the sorted offsets to the list
366+ return list . map ( ( item ) => {
367+ let [ offset , rule ] = item
368+
369+ offset = {
370+ ...offset ,
371+ propertyOffset : offsets . get ( offset . property ) ?? 0n ,
372+ }
373+
374+ return [ offset , rule ]
375+ } )
376+ }
377+
323378 /**
324379 * @template T
325380 * @param {[RuleOffset, T][] } list
326381 * @returns {[RuleOffset, T][] }
327382 */
328383 sort ( list ) {
384+ // Sort arbitrary variants so they're in alphabetical order
329385 list = this . remapArbitraryVariantOffsets ( list )
330386
387+ // Sort arbitrary properties so they're in alphabetical order
388+ list = this . sortArbitraryProperties ( list )
389+
331390 return list . sort ( ( [ a ] , [ b ] ) => bigSign ( this . compare ( a , b ) ) )
332391 }
333392}
0 commit comments