@@ -6,10 +6,12 @@ import {
66 type CssCommentAST ,
77 type CssCommonPositionAST ,
88 type CssContainerAST ,
9+ type CssCounterStyleAST ,
910 type CssCustomMediaAST ,
1011 type CssDeclarationAST ,
1112 type CssDocumentAST ,
1213 type CssFontFaceAST ,
14+ type CssFontFeatureValuesAST ,
1315 type CssGenericAtRuleAST ,
1416 type CssHostAST ,
1517 type CssImportAST ,
@@ -19,10 +21,14 @@ import {
1921 type CssMediaAST ,
2022 type CssNamespaceAST ,
2123 type CssPageAST ,
24+ type CssPositionTryAST ,
25+ type CssPropertyAST ,
2226 type CssRuleAST ,
27+ type CssScopeAST ,
2328 type CssStartingStyleAST ,
2429 type CssStylesheetAST ,
2530 type CssSupportsAST ,
31+ type CssViewTransitionAST ,
2632 CssTypes ,
2733} from '../type' ;
2834import {
@@ -688,14 +694,26 @@ export const parse = (
688694 if ( ! open ( ) ) {
689695 return error ( "@page missing '{'" ) ;
690696 }
691- let decls = comments < CssDeclarationAST > ( ) ;
697+ const decls : Array < CssDeclarationAST | CssCommentAST | CssAtRuleAST > = [ ] ;
698+ comments ( decls ) ;
692699
693- // declarations
694- let decl : CssDeclarationAST | undefined = declaration ( ) ;
695- while ( decl ) {
696- decls . push ( decl ) ;
697- decls = decls . concat ( comments ( ) ) ;
698- decl = declaration ( ) ;
700+ // declarations and nested at-rules (margin boxes)
701+ while ( css . length && css . charAt ( 0 ) !== '}' ) {
702+ if ( css . charAt ( 0 ) === '@' ) {
703+ const ar = atRule ( ) ;
704+ if ( ar ) {
705+ decls . push ( ar ) ;
706+ comments ( decls ) ;
707+ continue ;
708+ }
709+ }
710+ const decl = declaration ( ) ;
711+ if ( decl ) {
712+ decls . push ( decl ) ;
713+ comments ( decls ) ;
714+ continue ;
715+ }
716+ break ;
699717 }
700718
701719 if ( ! close ( ) ) {
@@ -775,6 +793,189 @@ export const parse = (
775793 } ) ;
776794 }
777795
796+ /**
797+ * Parse @property.
798+ */
799+ function atProperty ( ) : CssPropertyAST | undefined {
800+ const pos = position ( ) ;
801+ const m = / ^ @ p r o p e r t y \s + ( - - [ - \w ] + ) \s * / . exec ( css ) ;
802+ if ( ! m ) {
803+ return ;
804+ }
805+ const name = processMatch ( m ) [ 1 ] ;
806+
807+ if ( ! open ( ) ) {
808+ return error ( "@property missing '{'" ) ;
809+ }
810+ let decls = comments < CssDeclarationAST > ( ) ;
811+ let decl : CssDeclarationAST | undefined = declaration ( ) ;
812+ while ( decl ) {
813+ decls . push ( decl ) ;
814+ decls = decls . concat ( comments ( ) ) ;
815+ decl = declaration ( ) ;
816+ }
817+ if ( ! close ( ) ) {
818+ return error ( "@property missing '}'" ) ;
819+ }
820+
821+ return pos < CssPropertyAST > ( {
822+ type : CssTypes . property ,
823+ name : name ,
824+ declarations : decls ,
825+ } ) ;
826+ }
827+
828+ /**
829+ * Parse @counter-style.
830+ */
831+ function atCounterStyle ( ) : CssCounterStyleAST | undefined {
832+ const pos = position ( ) ;
833+ const m = / ^ @ c o u n t e r - s t y l e \s + ( [ - \w ] + ) \s * / . exec ( css ) ;
834+ if ( ! m ) {
835+ return ;
836+ }
837+ const name = processMatch ( m ) [ 1 ] ;
838+
839+ if ( ! open ( ) ) {
840+ return error ( "@counter-style missing '{'" ) ;
841+ }
842+ let decls = comments < CssDeclarationAST > ( ) ;
843+ let decl : CssDeclarationAST | undefined = declaration ( ) ;
844+ while ( decl ) {
845+ decls . push ( decl ) ;
846+ decls = decls . concat ( comments ( ) ) ;
847+ decl = declaration ( ) ;
848+ }
849+ if ( ! close ( ) ) {
850+ return error ( "@counter-style missing '}'" ) ;
851+ }
852+
853+ return pos < CssCounterStyleAST > ( {
854+ type : CssTypes . counterStyle ,
855+ name : name ,
856+ declarations : decls ,
857+ } ) ;
858+ }
859+
860+ /**
861+ * Parse @font-feature-values.
862+ */
863+ function atFontFeatureValues ( ) : CssFontFeatureValuesAST | undefined {
864+ const pos = position ( ) ;
865+ const m = / ^ @ f o n t - f e a t u r e - v a l u e s \s + ( [ ^ { ] + ) / . exec ( css ) ;
866+ if ( ! m ) {
867+ return ;
868+ }
869+ const fontFamily = trim ( processMatch ( m ) [ 1 ] ) ;
870+
871+ if ( ! open ( ) ) {
872+ return error ( "@font-feature-values missing '{'" ) ;
873+ }
874+
875+ const style = rulesOrDeclarations ( ) ;
876+
877+ if ( ! close ( ) ) {
878+ return error ( "@font-feature-values missing '}'" ) ;
879+ }
880+
881+ return pos < CssFontFeatureValuesAST > ( {
882+ type : CssTypes . fontFeatureValues ,
883+ fontFamily : fontFamily ,
884+ rules : style ,
885+ } ) ;
886+ }
887+
888+ /**
889+ * Parse @scope.
890+ */
891+ function atScope ( ) : CssScopeAST | undefined {
892+ const pos = position ( ) ;
893+ const m = / ^ @ s c o p e \s * ( [ ^ { ] * ) / . exec ( css ) ;
894+ if ( ! m ) {
895+ return ;
896+ }
897+ const scope = trim ( processMatch ( m ) [ 1 ] ) ;
898+
899+ if ( ! open ( ) ) {
900+ return error ( "@scope missing '{'" ) ;
901+ }
902+
903+ const style = rulesOrDeclarations ( ) ;
904+
905+ if ( ! close ( ) ) {
906+ return error ( "@scope missing '}'" ) ;
907+ }
908+
909+ return pos < CssScopeAST > ( {
910+ type : CssTypes . scope ,
911+ scope : scope ,
912+ rules : style ,
913+ } ) ;
914+ }
915+
916+ /**
917+ * Parse @view-transition.
918+ */
919+ function atViewTransition ( ) : CssViewTransitionAST | undefined {
920+ const pos = position ( ) ;
921+ const m = / ^ @ v i e w - t r a n s i t i o n \s * / . exec ( css ) ;
922+ if ( ! m ) {
923+ return ;
924+ }
925+ processMatch ( m ) ;
926+
927+ if ( ! open ( ) ) {
928+ return error ( "@view-transition missing '{'" ) ;
929+ }
930+ let decls = comments < CssDeclarationAST > ( ) ;
931+ let decl : CssDeclarationAST | undefined = declaration ( ) ;
932+ while ( decl ) {
933+ decls . push ( decl ) ;
934+ decls = decls . concat ( comments ( ) ) ;
935+ decl = declaration ( ) ;
936+ }
937+ if ( ! close ( ) ) {
938+ return error ( "@view-transition missing '}'" ) ;
939+ }
940+
941+ return pos < CssViewTransitionAST > ( {
942+ type : CssTypes . viewTransition ,
943+ declarations : decls ,
944+ } ) ;
945+ }
946+
947+ /**
948+ * Parse @position-try.
949+ */
950+ function atPositionTry ( ) : CssPositionTryAST | undefined {
951+ const pos = position ( ) ;
952+ const m = / ^ @ p o s i t i o n - t r y \s + ( - - [ - \w ] + ) \s * / . exec ( css ) ;
953+ if ( ! m ) {
954+ return ;
955+ }
956+ const name = processMatch ( m ) [ 1 ] ;
957+
958+ if ( ! open ( ) ) {
959+ return error ( "@position-try missing '{'" ) ;
960+ }
961+ let decls = comments < CssDeclarationAST > ( ) ;
962+ let decl : CssDeclarationAST | undefined = declaration ( ) ;
963+ while ( decl ) {
964+ decls . push ( decl ) ;
965+ decls = decls . concat ( comments ( ) ) ;
966+ decl = declaration ( ) ;
967+ }
968+ if ( ! close ( ) ) {
969+ return error ( "@position-try missing '}'" ) ;
970+ }
971+
972+ return pos < CssPositionTryAST > ( {
973+ type : CssTypes . positionTry ,
974+ name : name ,
975+ declarations : decls ,
976+ } ) ;
977+ }
978+
778979 /**
779980 * Parse starting style.
780981 */
@@ -913,9 +1114,15 @@ export const parse = (
9131114 atPage ( ) ||
9141115 atHost ( ) ||
9151116 atFontFace ( ) ||
1117+ atFontFeatureValues ( ) ||
9161118 atContainer ( ) ||
9171119 atStartingStyle ( ) ||
9181120 atLayer ( ) ||
1121+ atProperty ( ) ||
1122+ atCounterStyle ( ) ||
1123+ atScope ( ) ||
1124+ atViewTransition ( ) ||
1125+ atPositionTry ( ) ||
9191126 atGeneric ( )
9201127 ) ;
9211128 }
0 commit comments