@@ -14,6 +14,8 @@ import {
1414 PRELUDE_OPERATOR ,
1515 URL ,
1616 FUNCTION ,
17+ DIMENSION ,
18+ FEATURE_RANGE ,
1719} from './arena'
1820
1921describe ( 'At-Rule Prelude Nodes' , ( ) => {
@@ -425,7 +427,7 @@ describe('At-Rule Prelude Nodes', () => {
425427
426428 // Feature should have content
427429 const feature = queryChildren . find ( ( c ) => c . type === MEDIA_FEATURE )
428- expect ( feature ?. value ) . toContain ( 'min-width' )
430+ expect ( feature ?. name ) . toBe ( 'min-width' )
429431 } )
430432
431433 it ( 'should trim whitespace and comments from media features' , ( ) => {
@@ -436,7 +438,7 @@ describe('At-Rule Prelude Nodes', () => {
436438 const queryChildren = children [ 0 ] . children
437439 const feature = queryChildren . find ( ( c ) => c . type === MEDIA_FEATURE )
438440
439- expect ( feature ?. value ) . toBe ( 'min-width: 768px ' )
441+ expect ( feature ?. name ) . toBe ( 'min-width' )
440442 } )
441443
442444 it ( 'should parse complex media query with and operator' , ( ) => {
@@ -465,6 +467,128 @@ describe('At-Rule Prelude Nodes', () => {
465467 expect ( features . length ) . toBe ( 2 )
466468 } )
467469
470+ it ( 'should extract feature name from standard feature' , ( ) => {
471+ const css = '@media (orientation: portrait) { }'
472+ const ast = parse ( css )
473+ const atRule = ast . first_child
474+ const queryChildren = atRule ?. children [ 0 ] . children || [ ]
475+ const feature = queryChildren . find ( ( c ) => c . type === MEDIA_FEATURE )
476+
477+ expect ( feature ?. name ) . toBe ( 'orientation' )
478+ expect ( feature ?. children . length ) . toBe ( 1 )
479+ expect ( feature ?. children [ 0 ] . type ) . toBe ( IDENTIFIER )
480+ } )
481+
482+ it ( 'should extract feature name from boolean feature' , ( ) => {
483+ const css = '@media (hover) { }'
484+ const ast = parse ( css )
485+ const atRule = ast . first_child
486+ const queryChildren = atRule ?. children [ 0 ] . children || [ ]
487+ const feature = queryChildren . find ( ( c ) => c . type === MEDIA_FEATURE )
488+
489+ expect ( feature ?. name ) . toBe ( 'hover' )
490+ } )
491+
492+ it ( 'should parse feature values as typed children' , ( ) => {
493+ const css = '@media (min-width: 768px) { }'
494+ const ast = parse ( css )
495+ const atRule = ast . first_child
496+ const queryChildren = atRule ?. children [ 0 ] . children || [ ]
497+ const feature = queryChildren . find ( ( c ) => c . type === MEDIA_FEATURE )
498+
499+ expect ( feature ?. name ) . toBe ( 'min-width' )
500+ expect ( feature ?. children . length ) . toBe ( 1 )
501+ expect ( feature ?. children [ 0 ] . type ) . toBe ( DIMENSION )
502+ } )
503+
504+ it ( 'should parse identifier value as child' , ( ) => {
505+ const css = '@media (orientation: portrait) { }'
506+ const ast = parse ( css )
507+ const atRule = ast . first_child
508+ const queryChildren = atRule ?. children [ 0 ] . children || [ ]
509+ const feature = queryChildren . find ( ( c ) => c . type === MEDIA_FEATURE )
510+
511+ expect ( feature ?. children . length ) . toBe ( 1 )
512+ expect ( feature ?. children [ 0 ] . type ) . toBe ( IDENTIFIER )
513+ expect ( feature ?. children [ 0 ] . text ) . toBe ( 'portrait' )
514+ } )
515+
516+ it ( 'should have no children for boolean features' , ( ) => {
517+ const css = '@media (hover) { }'
518+ const ast = parse ( css )
519+ const atRule = ast . first_child
520+ const queryChildren = atRule ?. children [ 0 ] . children || [ ]
521+ const feature = queryChildren . find ( ( c ) => c . type === MEDIA_FEATURE )
522+
523+ expect ( feature ?. children . length ) . toBe ( 0 )
524+ } )
525+
526+ it ( 'should parse range syntax with single comparison' , ( ) => {
527+ const css = '@media (width >= 400px) { }'
528+ const ast = parse ( css )
529+ const atRule = ast . first_child
530+ const queryChildren = atRule ?. children [ 0 ] . children || [ ]
531+ const range = queryChildren . find ( ( c ) => c . type === FEATURE_RANGE )
532+
533+ expect ( range ?. type ) . toBe ( FEATURE_RANGE )
534+ expect ( range ?. name ) . toBe ( 'width' )
535+ expect ( range ?. children . length ) . toBe ( 2 ) // dimension + operator
536+
537+ // Verify child types
538+ expect ( range ?. children [ 0 ] . type ) . toBe ( PRELUDE_OPERATOR ) // >=
539+ expect ( range ?. children [ 1 ] . type ) . toBe ( DIMENSION ) // 400px
540+ } )
541+
542+ it ( 'should parse range syntax with double comparison' , ( ) => {
543+ const css = '@media (50px <= width <= 100px) { }'
544+ const ast = parse ( css )
545+ const atRule = ast . first_child
546+ const queryChildren = atRule ?. children [ 0 ] . children || [ ]
547+ const range = queryChildren . find ( ( c ) => c . type === FEATURE_RANGE )
548+
549+ expect ( range ?. type ) . toBe ( FEATURE_RANGE )
550+ expect ( range ?. name ) . toBe ( 'width' )
551+ expect ( range ?. children . length ) . toBe ( 4 ) // dim, op, op, dim
552+
553+ // Verify child types
554+ expect ( range ?. children [ 0 ] . type ) . toBe ( DIMENSION ) // 50px
555+ expect ( range ?. children [ 1 ] . type ) . toBe ( PRELUDE_OPERATOR ) // <=
556+ expect ( range ?. children [ 2 ] . type ) . toBe ( PRELUDE_OPERATOR ) // <=
557+ expect ( range ?. children [ 3 ] . type ) . toBe ( DIMENSION ) // 100px
558+ } )
559+
560+ it ( 'should parse range syntax with less-than' , ( ) => {
561+ const css = '@media (400px < width) { }'
562+ const ast = parse ( css )
563+ const atRule = ast . first_child
564+ const queryChildren = atRule ?. children [ 0 ] . children || [ ]
565+ const range = queryChildren . find ( ( c ) => c . type === FEATURE_RANGE )
566+
567+ expect ( range ?. type ) . toBe ( FEATURE_RANGE )
568+ expect ( range ?. name ) . toBe ( 'width' )
569+ expect ( range ?. children . length ) . toBe ( 2 )
570+
571+ // Verify child types
572+ expect ( range ?. children [ 0 ] . type ) . toBe ( DIMENSION ) // 400px
573+ expect ( range ?. children [ 1 ] . type ) . toBe ( PRELUDE_OPERATOR ) // <
574+ } )
575+
576+ it ( 'should parse range syntax with equals' , ( ) => {
577+ const css = '@media (width = 500px) { }'
578+ const ast = parse ( css )
579+ const atRule = ast . first_child
580+ const queryChildren = atRule ?. children [ 0 ] . children || [ ]
581+ const range = queryChildren . find ( ( c ) => c . type === FEATURE_RANGE )
582+
583+ expect ( range ?. type ) . toBe ( FEATURE_RANGE )
584+ expect ( range ?. name ) . toBe ( 'width' )
585+ expect ( range ?. children . length ) . toBe ( 2 )
586+
587+ // Verify child types
588+ expect ( range ?. children [ 0 ] . type ) . toBe ( PRELUDE_OPERATOR ) // =
589+ expect ( range ?. children [ 1 ] . type ) . toBe ( DIMENSION ) // 500px
590+ } )
591+
468592 it ( 'should parse comma-separated media queries' , ( ) => {
469593 const css = '@media screen, print { }'
470594 const ast = parse ( css )
@@ -474,6 +598,11 @@ describe('At-Rule Prelude Nodes', () => {
474598 // Should have 2 media query nodes
475599 const queries = children . filter ( ( c ) => c . type === MEDIA_QUERY )
476600 expect ( queries . length ) . toBe ( 2 )
601+ const [ screen , print ] = queries
602+ expect ( screen . type_name ) . toBe ( 'MediaQuery' )
603+ expect ( screen . text ) . toBe ( 'screen' )
604+ expect ( print . type_name ) . toBe ( 'MediaQuery' )
605+ expect ( print . text ) . toBe ( 'print' )
477606 } )
478607 } )
479608
0 commit comments