@@ -707,4 +707,275 @@ describe('parse_atrule_prelude()', () => {
707707 expect ( result . length ) . toBeGreaterThan ( 0 )
708708 } )
709709 } )
710+
711+ describe ( 'length property correctness (regression tests for commit 5c6e2cd)' , ( ) => {
712+ describe ( 'At-rule prelude length' , ( ) => {
713+ test ( '@media prelude length should match text' , ( ) => {
714+ const css = '@media screen { }'
715+ const ast = parse ( css )
716+ const atRule = ast . first_child
717+
718+ expect ( atRule ?. prelude ) . toBe ( 'screen' )
719+ expect ( atRule ?. prelude ?. length ) . toBe ( 6 )
720+ } )
721+
722+ test ( '@media with feature prelude length' , ( ) => {
723+ const css = '@media (min-width: 768px) { }'
724+ const ast = parse ( css )
725+ const atRule = ast . first_child
726+
727+ expect ( atRule ?. prelude ) . toBe ( '(min-width: 768px)' )
728+ expect ( atRule ?. prelude ?. length ) . toBe ( 18 )
729+ } )
730+
731+ test ( '@media complex prelude length' , ( ) => {
732+ const css = '@media screen and (min-width: 768px) { }'
733+ const ast = parse ( css )
734+ const atRule = ast . first_child
735+
736+ expect ( atRule ?. prelude ) . toBe ( 'screen and (min-width: 768px)' )
737+ expect ( atRule ?. prelude ?. length ) . toBe ( 29 )
738+ } )
739+
740+ test ( '@container prelude length' , ( ) => {
741+ const css = '@container (min-width: 768px) { }'
742+ const ast = parse ( css )
743+ const atRule = ast . first_child
744+
745+ expect ( atRule ?. prelude ) . toBe ( '(min-width: 768px)' )
746+ expect ( atRule ?. prelude ?. length ) . toBe ( 18 )
747+ } )
748+
749+ test ( '@container with name prelude length' , ( ) => {
750+ const css = '@container sidebar (min-width: 400px) { }'
751+ const ast = parse ( css )
752+ const atRule = ast . first_child
753+
754+ expect ( atRule ?. prelude ) . toBe ( 'sidebar (min-width: 400px)' )
755+ expect ( atRule ?. prelude ?. length ) . toBe ( 26 )
756+ } )
757+
758+ test ( '@supports prelude length' , ( ) => {
759+ const css = '@supports (display: flex) { }'
760+ const ast = parse ( css )
761+ const atRule = ast . first_child
762+
763+ expect ( atRule ?. prelude ) . toBe ( '(display: flex)' )
764+ expect ( atRule ?. prelude ?. length ) . toBe ( 15 )
765+ } )
766+
767+ test ( '@supports complex prelude length' , ( ) => {
768+ const css = '@supports (display: flex) and (color: red) { }'
769+ const ast = parse ( css )
770+ const atRule = ast . first_child
771+
772+ expect ( atRule ?. prelude ) . toBe ( '(display: flex) and (color: red)' )
773+ expect ( atRule ?. prelude ?. length ) . toBe ( 32 )
774+ } )
775+
776+ test ( '@layer single name prelude length' , ( ) => {
777+ const css = '@layer utilities { }'
778+ const ast = parse ( css )
779+ const atRule = ast . first_child
780+
781+ expect ( atRule ?. prelude ) . toBe ( 'utilities' )
782+ expect ( atRule ?. prelude ?. length ) . toBe ( 9 )
783+ } )
784+
785+ test ( '@layer multiple names prelude length' , ( ) => {
786+ const css = '@layer base, components, utilities { }'
787+ const ast = parse ( css )
788+ const atRule = ast . first_child
789+
790+ expect ( atRule ?. prelude ) . toBe ( 'base, components, utilities' )
791+ expect ( atRule ?. prelude ?. length ) . toBe ( 27 )
792+ } )
793+
794+ test ( '@import url prelude length' , ( ) => {
795+ const css = '@import url("styles.css") screen;'
796+ const ast = parse ( css )
797+ const atRule = ast . first_child
798+
799+ expect ( atRule ?. prelude ) . toBe ( 'url("styles.css") screen' )
800+ expect ( atRule ?. prelude ?. length ) . toBe ( 24 )
801+ } )
802+
803+ test ( '@import with layer prelude length' , ( ) => {
804+ const css = '@import "styles.css" layer(utilities);'
805+ const ast = parse ( css )
806+ const atRule = ast . first_child
807+
808+ expect ( atRule ?. prelude ) . toBe ( '"styles.css" layer(utilities)' )
809+ expect ( atRule ?. prelude ?. length ) . toBe ( 29 )
810+ } )
811+
812+ test ( '@import with supports prelude length' , ( ) => {
813+ const css = '@import url("styles.css") supports(display: flex);'
814+ const ast = parse ( css )
815+ const atRule = ast . first_child
816+
817+ expect ( atRule ?. prelude ) . toBe ( 'url("styles.css") supports(display: flex)' )
818+ expect ( atRule ?. prelude ?. length ) . toBe ( 41 )
819+ } )
820+
821+ test ( '@import complex prelude length' , ( ) => {
822+ const css = '@import url("a.css") layer(utilities) supports(display: flex) screen;'
823+ const ast = parse ( css )
824+ const atRule = ast . first_child
825+
826+ expect ( atRule ?. prelude ) . toBe ( 'url("a.css") layer(utilities) supports(display: flex) screen' )
827+ expect ( atRule ?. prelude ?. length ) . toBe ( 60 )
828+ } )
829+ } )
830+
831+ describe ( 'Prelude child node text length' , ( ) => {
832+ test ( 'media query node text length' , ( ) => {
833+ const css = '@media screen and (min-width: 768px) { }'
834+ const ast = parse ( css )
835+ const atRule = ast . first_child
836+ const children = atRule ?. children || [ ]
837+
838+ // First child should be media query
839+ const mediaQuery = children [ 0 ]
840+ expect ( mediaQuery . type ) . toBe ( NODE_PRELUDE_MEDIA_QUERY )
841+ expect ( mediaQuery . text ) . toBe ( 'screen and (min-width: 768px)' )
842+ expect ( mediaQuery . text . length ) . toBe ( 29 )
843+ } )
844+
845+ test ( 'media type node text length' , ( ) => {
846+ const css = '@media screen { }'
847+ const ast = parse ( css )
848+ const atRule = ast . first_child
849+ const children = atRule ?. children || [ ]
850+ const mediaQuery = children [ 0 ]
851+ const queryChildren = mediaQuery ?. children || [ ]
852+
853+ const mediaType = queryChildren . find ( ( c ) => c . type === NODE_PRELUDE_MEDIA_TYPE )
854+ expect ( mediaType ?. text ) . toBe ( 'screen' )
855+ expect ( mediaType ?. text . length ) . toBe ( 6 )
856+ } )
857+
858+ test ( 'media feature node text length' , ( ) => {
859+ const css = '@media (min-width: 768px) { }'
860+ const ast = parse ( css )
861+ const atRule = ast . first_child
862+ const children = atRule ?. children || [ ]
863+ const mediaQuery = children [ 0 ]
864+ const queryChildren = mediaQuery ?. children || [ ]
865+
866+ const mediaFeature = queryChildren . find ( ( c ) => c . type === NODE_PRELUDE_MEDIA_FEATURE )
867+ expect ( mediaFeature ?. text ) . toBe ( '(min-width: 768px)' )
868+ expect ( mediaFeature ?. text . length ) . toBe ( 18 )
869+ } )
870+
871+ test ( 'container query node text length' , ( ) => {
872+ const css = '@container sidebar (min-width: 400px) { }'
873+ const ast = parse ( css )
874+ const atRule = ast . first_child
875+ const children = atRule ?. children || [ ]
876+
877+ const containerQuery = children . find ( ( c ) => c . type === NODE_PRELUDE_CONTAINER_QUERY )
878+ expect ( containerQuery ?. text ) . toBe ( 'sidebar (min-width: 400px)' )
879+ expect ( containerQuery ?. text . length ) . toBe ( 26 )
880+ } )
881+
882+ test ( 'supports query node text length' , ( ) => {
883+ const css = '@supports (display: flex) { }'
884+ const ast = parse ( css )
885+ const atRule = ast . first_child
886+ const children = atRule ?. children || [ ]
887+
888+ const supportsQuery = children . find ( ( c ) => c . type === NODE_PRELUDE_SUPPORTS_QUERY )
889+ expect ( supportsQuery ?. text ) . toBe ( '(display: flex)' )
890+ expect ( supportsQuery ?. text . length ) . toBe ( 15 )
891+ } )
892+
893+ test ( 'layer name node text length' , ( ) => {
894+ const css = '@layer utilities { }'
895+ const ast = parse ( css )
896+ const atRule = ast . first_child
897+ const children = atRule ?. children || [ ]
898+
899+ const layerName = children . find ( ( c ) => c . type === NODE_PRELUDE_LAYER_NAME )
900+ expect ( layerName ?. text ) . toBe ( 'utilities' )
901+ expect ( layerName ?. text . length ) . toBe ( 9 )
902+ } )
903+
904+ test ( 'import url node text length' , ( ) => {
905+ const css = '@import url("styles.css") screen;'
906+ const ast = parse ( css )
907+ const atRule = ast . first_child
908+ const children = atRule ?. children || [ ]
909+
910+ const importUrl = children . find ( ( c ) => c . type === NODE_PRELUDE_IMPORT_URL )
911+ expect ( importUrl ?. text ) . toBe ( 'url("styles.css")' )
912+ expect ( importUrl ?. text . length ) . toBe ( 17 )
913+ } )
914+
915+ test ( 'import layer node text length' , ( ) => {
916+ const css = '@import "styles.css" layer(utilities);'
917+ const ast = parse ( css )
918+ const atRule = ast . first_child
919+ const children = atRule ?. children || [ ]
920+
921+ const importLayer = children . find ( ( c ) => c . type === NODE_PRELUDE_IMPORT_LAYER )
922+ expect ( importLayer ?. text ) . toBe ( 'layer(utilities)' )
923+ expect ( importLayer ?. text . length ) . toBe ( 16 )
924+ } )
925+
926+ test ( 'import supports node text length' , ( ) => {
927+ const css = '@import url("a.css") supports(display: flex);'
928+ const ast = parse ( css )
929+ const atRule = ast . first_child
930+ const children = atRule ?. children || [ ]
931+
932+ const importSupports = children . find ( ( c ) => c . type === NODE_PRELUDE_IMPORT_SUPPORTS )
933+ expect ( importSupports ?. text ) . toBe ( 'supports(display: flex)' )
934+ expect ( importSupports ?. text . length ) . toBe ( 23 )
935+ } )
936+
937+ test ( 'operator node text length' , ( ) => {
938+ const css = '@media screen and (min-width: 768px) { }'
939+ const ast = parse ( css )
940+ const atRule = ast . first_child
941+ const children = atRule ?. children || [ ]
942+ const mediaQuery = children [ 0 ]
943+ const queryChildren = mediaQuery ?. children || [ ]
944+
945+ const operator = queryChildren . find ( ( c ) => c . type === NODE_PRELUDE_OPERATOR )
946+ expect ( operator ?. text ) . toBe ( 'and' )
947+ expect ( operator ?. text . length ) . toBe ( 3 )
948+ } )
949+ } )
950+
951+ describe ( 'Edge cases and whitespace handling' , ( ) => {
952+ test ( '@media with extra whitespace prelude length' , ( ) => {
953+ const css = '@media screen and (min-width: 768px) { }'
954+ const ast = parse ( css )
955+ const atRule = ast . first_child
956+
957+ // Whitespace is trimmed from start/end but preserved internally
958+ expect ( atRule ?. prelude ) . toBe ( 'screen and (min-width: 768px)' )
959+ expect ( atRule ?. prelude ?. length ) . toBe ( 33 )
960+ } )
961+
962+ test ( '@layer with whitespace around commas' , ( ) => {
963+ const css = '@layer base , components , utilities { }'
964+ const ast = parse ( css )
965+ const atRule = ast . first_child
966+
967+ expect ( atRule ?. prelude ) . toBe ( 'base , components , utilities' )
968+ expect ( atRule ?. prelude ?. length ) . toBe ( 29 )
969+ } )
970+
971+ test ( '@import with newlines prelude length' , ( ) => {
972+ const css = '@import url("styles.css")\n screen;'
973+ const ast = parse ( css )
974+ const atRule = ast . first_child
975+
976+ expect ( atRule ?. prelude ) . toBe ( 'url("styles.css")\n screen' )
977+ expect ( atRule ?. prelude ?. length ) . toBe ( 26 )
978+ } )
979+ } )
980+ } )
710981} )
0 commit comments