@@ -379,55 +379,89 @@ function transformLiquid(ast, { env }) {
379
379
: node . name === 'class'
380
380
}
381
381
382
- function sortAttribute ( attr , path ) {
382
+ /**
383
+ * @param {string } str
384
+ */
385
+ function hasSurroundingQuotes ( str ) {
386
+ let start = str [ 0 ]
387
+ let end = str [ str . length - 1 ]
388
+
389
+ return start === end && ( start === '"' || start === "'" || start === "`" )
390
+ }
391
+
392
+ /** @type {{type: string, source: string}[] } */
393
+ let sources = [ ]
394
+
395
+ /** @type {{pos: {start: number, end: number}, value: string}[] } */
396
+ let changes = [ ]
397
+
398
+ function sortAttribute ( attr ) {
383
399
visit ( attr . value , {
384
400
TextNode ( node ) {
385
401
node . value = sortClasses ( node . value , { env } ) ;
386
-
387
- let source = node . source . slice ( 0 , node . position . start ) + node . value + node . source . slice ( node . position . end )
388
- path . forEach ( node => ( node . source = source ) )
402
+ changes . push ( {
403
+ pos : node . position ,
404
+ value : node . value ,
405
+ } )
389
406
} ,
390
407
391
408
String ( node ) {
392
- node . value = sortClasses ( node . value , { env } ) ;
409
+ let pos = { ...node . position }
410
+
411
+ // We have to offset the position ONLY when quotes are part of the String node
412
+ // This is because `value` does NOT include quotes
413
+ if ( hasSurroundingQuotes ( node . source . slice ( pos . start , pos . end ) ) ) {
414
+ pos . start += 1 ;
415
+ pos . end -= 1 ;
416
+ }
393
417
394
- // String position includes the quotes even if the value doesn't
395
- // Hence the +1 and -1 when slicing
396
- let source = node . source . slice ( 0 , node . position . start + 1 ) + node . value + node . source . slice ( node . position . end - 1 )
397
- path . forEach ( node => ( node . source = source ) )
418
+ node . value = sortClasses ( node . value , { env } )
419
+ changes . push ( {
420
+ pos,
421
+ value : node . value ,
422
+ } )
398
423
} ,
399
424
} )
400
425
}
401
426
402
427
visit ( ast , {
403
- LiquidTag ( node , _parent , _key , _index , meta ) {
404
- meta . path = [ ... meta . path ?? [ ] , node ] ;
428
+ LiquidTag ( node ) {
429
+ sources . push ( node )
405
430
} ,
406
431
407
- HtmlElement ( node , _parent , _key , _index , meta ) {
408
- meta . path = [ ... meta . path ?? [ ] , node ] ;
432
+ HtmlElement ( node ) {
433
+ sources . push ( node )
409
434
} ,
410
435
411
- AttrSingleQuoted ( node , _parent , _key , _index , meta ) {
412
- if ( ! isClassAttr ( node ) ) {
413
- return ;
436
+ AttrSingleQuoted ( node ) {
437
+ if ( isClassAttr ( node ) ) {
438
+ sources . push ( node )
439
+ sortAttribute ( node )
414
440
}
415
-
416
- meta . path = [ ...meta . path ?? [ ] , node ] ;
417
-
418
- sortAttribute ( node , meta . path )
419
441
} ,
420
442
421
- AttrDoubleQuoted ( node , _parent , _key , _index , meta ) {
422
- if ( ! isClassAttr ( node ) ) {
423
- return ;
443
+ AttrDoubleQuoted ( node ) {
444
+ if ( isClassAttr ( node ) ) {
445
+ sources . push ( node )
446
+ sortAttribute ( node )
424
447
}
425
-
426
- meta . path = [ ...meta . path ?? [ ] , node ] ;
427
-
428
- sortAttribute ( node , meta . path )
429
448
} ,
430
449
} ) ;
450
+
451
+ // Sort so all changes occur in order
452
+ changes = changes . sort ( ( a , b ) => {
453
+ return a . start - b . start
454
+ || a . end - b . end
455
+ } )
456
+
457
+ for ( let change of changes ) {
458
+ for ( let node of sources ) {
459
+ node . source =
460
+ node . source . slice ( 0 , change . pos . start ) +
461
+ change . value +
462
+ node . source . slice ( change . pos . end )
463
+ }
464
+ }
431
465
}
432
466
433
467
function sortStringLiteral ( node , { env } ) {
0 commit comments