@@ -4,6 +4,7 @@ import visitors from '../visitors';
44import getParserInput from './parser-input' ;
55import * as utils from '../utils' ;
66import functionRegistry from '../functions/function-registry' ;
7+ import { ContainerSyntaxOptions , MediaSyntaxOptions } from '../tree/atrule-syntax' ;
78
89//
910// less.js - parser
@@ -1698,7 +1699,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
16981699 const options = ( dir ? this . importOptions ( ) : null ) || { } ;
16991700
17001701 if ( ( path = this . entities . quoted ( ) || this . entities . url ( ) ) ) {
1701- features = this . mediaFeatures ( ) ;
1702+ features = this . mediaFeatures ( { } ) ;
17021703
17031704 if ( ! parserInput . $char ( ';' ) ) {
17041705 parserInput . i = index ;
@@ -1752,22 +1753,39 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
17521753 }
17531754 } ,
17541755
1755- mediaFeature : function ( ) {
1756+ mediaFeature : function ( syntaxOptions ) {
17561757 const entities = this . entities ;
17571758 const nodes = [ ] ;
17581759 let e ;
17591760 let p ;
1761+ let rangeP ;
17601762 parserInput . save ( ) ;
17611763 do {
17621764 e = entities . keyword ( ) || entities . variable ( ) || entities . mixinLookup ( ) ;
17631765 if ( e ) {
17641766 nodes . push ( e ) ;
17651767 } else if ( parserInput . $char ( '(' ) ) {
17661768 p = this . property ( ) ;
1767- e = this . value ( ) ;
1769+ parserInput . save ( ) ;
1770+ if ( ! p && syntaxOptions . queryInParens && parserInput . $re ( / ^ [ 0 - 9 a - z - ] * \s * ( [ < > ] = | < = | > = | [ < > ] | = ) / ) ) {
1771+ parserInput . restore ( ) ;
1772+ p = this . condition ( ) ;
1773+
1774+ parserInput . save ( ) ;
1775+ rangeP = this . atomicCondition ( null , p . rvalue ) ;
1776+ if ( ! rangeP ) {
1777+ parserInput . restore ( ) ;
1778+ }
1779+ } else {
1780+ parserInput . restore ( ) ;
1781+ e = this . value ( ) ;
1782+ }
17681783 if ( parserInput . $char ( ')' ) ) {
1769- if ( p && e ) {
1770- nodes . push ( new ( tree . Paren ) ( new ( tree . Declaration ) ( p , e , null , null , parserInput . i + currentIndex , fileInfo , true ) ) ) ;
1784+ if ( p && ! e ) {
1785+ nodes . push ( new ( tree . Paren ) ( new ( tree . QueryInParens ) ( p . op , p . lvalue , p . rvalue , rangeP ? rangeP . op : null , rangeP ? rangeP . rvalue : null , p . _index ) ) ) ;
1786+ e = p ;
1787+ } else if ( p && e ) {
1788+ nodes . push ( new ( tree . Paren ) ( new ( tree . Declaration ) ( p , e , null , null , parserInput . i + currentIndex , fileInfo , true ) ) ) ;
17711789 } else if ( e ) {
17721790 nodes . push ( new ( tree . Paren ) ( e ) ) ;
17731791 } else {
@@ -1785,12 +1803,12 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
17851803 }
17861804 } ,
17871805
1788- mediaFeatures : function ( ) {
1806+ mediaFeatures : function ( syntaxOptions ) {
17891807 const entities = this . entities ;
17901808 const features = [ ] ;
17911809 let e ;
17921810 do {
1793- e = this . mediaFeature ( ) ;
1811+ e = this . mediaFeature ( syntaxOptions ) ;
17941812 if ( e ) {
17951813 features . push ( e ) ;
17961814 if ( ! parserInput . $char ( ',' ) ) { break ; }
@@ -1806,38 +1824,44 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
18061824 return features . length > 0 ? features : null ;
18071825 } ,
18081826
1809- media : function ( ) {
1810- let features ;
1811- let rules ;
1812- let media ;
1827+ prepareAndGetNestableAtRule : function ( treeType , index , debugInfo , syntaxOptions ) {
1828+ const features = this . mediaFeatures ( syntaxOptions ) ;
1829+
1830+ const rules = this . block ( ) ;
1831+
1832+ if ( ! rules ) {
1833+ error ( 'media definitions require block statements after any features' ) ;
1834+ }
1835+
1836+ parserInput . forget ( ) ;
1837+
1838+ const atRule = new ( treeType ) ( rules , features , index + currentIndex , fileInfo ) ;
1839+ if ( context . dumpLineNumbers ) {
1840+ atRule . debugInfo = debugInfo ;
1841+ }
1842+
1843+ return atRule ;
1844+ } ,
1845+
1846+ nestableAtRule : function ( ) {
18131847 let debugInfo ;
18141848 const index = parserInput . i ;
18151849
18161850 if ( context . dumpLineNumbers ) {
18171851 debugInfo = getDebugInfo ( index ) ;
18181852 }
1819-
18201853 parserInput . save ( ) ;
18211854
1822- if ( parserInput . $str ( '@media' ) ) {
1823- features = this . mediaFeatures ( ) ;
1824-
1825- rules = this . block ( ) ;
1826-
1827- if ( ! rules ) {
1828- error ( 'media definitions require block statements after any features' ) ;
1855+ if ( parserInput . $peekChar ( '@' ) ) {
1856+ if ( parserInput . $str ( '@media' ) ) {
1857+ return this . prepareAndGetNestableAtRule ( tree . Media , index , debugInfo , MediaSyntaxOptions ) ;
18291858 }
1830-
1831- parserInput . forget ( ) ;
1832-
1833- media = new ( tree . Media ) ( rules , features , index + currentIndex , fileInfo ) ;
1834- if ( context . dumpLineNumbers ) {
1835- media . debugInfo = debugInfo ;
1859+
1860+ if ( parserInput . $str ( '@container' ) ) {
1861+ return this . prepareAndGetNestableAtRule ( tree . Container , index , debugInfo , ContainerSyntaxOptions ) ;
18361862 }
1837-
1838- return media ;
18391863 }
1840-
1864+
18411865 parserInput . restore ( ) ;
18421866 } ,
18431867
@@ -1919,7 +1943,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
19191943
19201944 if ( parserInput . currentChar ( ) !== '@' ) { return ; }
19211945
1922- value = this [ 'import' ] ( ) || this . plugin ( ) || this . media ( ) ;
1946+ value = this [ 'import' ] ( ) || this . plugin ( ) || this . nestableAtRule ( ) ;
19231947 if ( value ) {
19241948 return value ;
19251949 }
@@ -2231,7 +2255,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
22312255 parserInput . forget ( ) ;
22322256 return body ;
22332257 } ,
2234- atomicCondition : function ( ) {
2258+ atomicCondition : function ( needsParens , preparsedCond ) {
22352259 const entities = this . entities ;
22362260 const index = parserInput . i ;
22372261 let a ;
@@ -2243,7 +2267,12 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
22432267 return this . addition ( ) || entities . keyword ( ) || entities . quoted ( ) || entities . mixinLookup ( ) ;
22442268 } ) . bind ( this )
22452269
2246- a = cond ( ) ;
2270+ if ( preparsedCond ) {
2271+ a = preparsedCond ;
2272+ } else {
2273+ a = cond ( ) ;
2274+ }
2275+
22472276 if ( a ) {
22482277 if ( parserInput . $char ( '>' ) ) {
22492278 if ( parserInput . $char ( '=' ) ) {
@@ -2275,7 +2304,7 @@ const Parser = function Parser(context, imports, fileInfo, currentIndex) {
22752304 } else {
22762305 error ( 'expected expression' ) ;
22772306 }
2278- } else {
2307+ } else if ( ! preparsedCond ) {
22792308 c = new ( tree . Condition ) ( '=' , a , new ( tree . Keyword ) ( 'true' ) , index + currentIndex , false ) ;
22802309 }
22812310 return c ;
@@ -2422,4 +2451,4 @@ Parser.serializeVars = vars => {
24222451 return s ;
24232452} ;
24242453
2425- export default Parser ;
2454+ export default Parser ;
0 commit comments