diff --git a/packages/media-query-list-parser/CHANGELOG.md b/packages/media-query-list-parser/CHANGELOG.md index b4c1351049..20d92fff43 100644 --- a/packages/media-query-list-parser/CHANGELOG.md +++ b/packages/media-query-list-parser/CHANGELOG.md @@ -2,6 +2,7 @@ ### Unreleased (patch) +- Fixed: avoid exponential parse times for deeply nested media conditions. - Updated [`@csstools/css-tokenizer`](https://github.com/csstools/postcss-plugins/tree/main/packages/css-tokenizer) to [`4.0.1`](https://github.com/csstools/postcss-plugins/tree/main/packages/css-tokenizer/CHANGELOG.md#401) (patch) ### 5.0.0 diff --git a/packages/media-query-list-parser/dist/index.mjs b/packages/media-query-list-parser/dist/index.mjs index 9a175ed238..49caa7c796 100644 --- a/packages/media-query-list-parser/dist/index.mjs +++ b/packages/media-query-list-parser/dist/index.mjs @@ -1 +1 @@ -import{walkerIndexGenerator as e,isTokenNode as t,isFunctionNode as i,ComponentValueType as a,isWhiteSpaceOrCommentNode as n,TokenNode as r,parseListOfComponentValues as s,isWhitespaceNode as o,isCommentNode as u,isSimpleBlockNode as d,parseCommaSeparatedListOfComponentValues as l}from"@csstools/css-parser-algorithms";import{stringify as h,isTokenWhiteSpaceOrComment as m,isTokenIdent as f,TokenType as c,isTokenNumber as M,isTokenDimension as p,isTokenDelim as y,isTokenColon as v,mutateIdent as g,isTokenOpenParen as k,tokenize as F,isTokenEOF as w,cloneTokens as N}from"@csstools/css-tokenizer";var O;!function(e){e.CustomMedia="custom-media",e.GeneralEnclosed="general-enclosed",e.MediaAnd="media-and",e.MediaCondition="media-condition",e.MediaConditionListWithAnd="media-condition-list-and",e.MediaConditionListWithOr="media-condition-list-or",e.MediaFeature="media-feature",e.MediaFeatureBoolean="mf-boolean",e.MediaFeatureName="mf-name",e.MediaFeaturePlain="mf-plain",e.MediaFeatureRangeNameValue="mf-range-name-value",e.MediaFeatureRangeValueName="mf-range-value-name",e.MediaFeatureRangeValueNameValue="mf-range-value-name-value",e.MediaFeatureValue="mf-value",e.MediaInParens="media-in-parens",e.MediaNot="media-not",e.MediaOr="media-or",e.MediaQueryWithType="media-query-with-type",e.MediaQueryWithoutType="media-query-without-type",e.MediaQueryInvalid="media-query-invalid"}(O||(O={}));class MediaCondition{type=O.MediaCondition;media;constructor(e){this.media=e}tokens(){return this.media.tokens()}toString(){return this.media.toString()}hasLeadingSpace(){return this.media.hasLeadingSpace()}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&this.media.walk(e,i)}toJSON(){return{type:this.type,media:this.media.toJSON()}}isMediaCondition(){return MediaCondition.isMediaCondition(this)}static isMediaCondition(e){return!!e&&(e instanceof MediaCondition&&e.type===O.MediaCondition)}}class MediaInParens{type=O.MediaInParens;media;before;after;constructor(e,t=[],i=[]){this.media=e,this.before=t,this.after=i}tokens(){return[...this.before,...this.media.tokens(),...this.after]}toString(){return h(...this.before)+this.media.toString()+h(...this.after)}hasLeadingSpace(){return this.before.length?m(this.before[0]):this.media.hasLeadingSpace()}indexOf(e){return e===this.media?"media":-1}at(e){if("media"===e)return this.media}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.media,parent:this,state:i},"media")&&("walk"in this.media?this.media.walk(e,i):void 0)}toJSON(){return{type:this.type,media:this.media.toJSON(),before:this.before,after:this.after}}isMediaInParens(){return MediaInParens.isMediaInParens(this)}static isMediaInParens(e){return!!e&&(e instanceof MediaInParens&&e.type===O.MediaInParens)}}class MediaQueryWithType{type=O.MediaQueryWithType;modifier;mediaType;and=void 0;media=void 0;constructor(e,t,i,a){this.modifier=e,this.mediaType=t,i&&a&&(this.and=i,this.media=a)}getModifier(){if(!this.modifier.length)return"";for(let e=0;ee.tokens())}toString(){return this.media.map(e=>e.toString()).join("")}walk(t,i){if(0===this.media.length)return;const a=e(this.media);let n=0;for(;ne.tokens()),...this.after]}toString(){return h(...this.before)+this.leading.toString()+this.list.map(e=>e.toString()).join("")+h(...this.after)}hasLeadingSpace(){return this.before.length?m(this.before[0]):this.leading.hasLeadingSpace()}indexOf(e){return e===this.leading?"leading":e.type===O.MediaAnd?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(t,i){let a;if(i&&(a={...i}),!1===t({node:this.leading,parent:this,state:a},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(t,a))return!1;if(0===this.list.length)return;const n=e(this.list);let r=0;for(;re.toJSON()),before:this.before,after:this.after}}isMediaConditionListWithAnd(){return MediaConditionListWithAnd.isMediaConditionListWithAnd(this)}static isMediaConditionListWithAnd(e){return!!e&&(e instanceof MediaConditionListWithAnd&&e.type===O.MediaConditionListWithAnd)}}class MediaConditionListWithOr{type=O.MediaConditionListWithOr;leading;list;before;after;constructor(e,t,i=[],a=[]){this.leading=e,this.list=t,this.before=i,this.after=a}tokens(){return[...this.before,...this.leading.tokens(),...this.list.flatMap(e=>e.tokens()),...this.after]}toString(){return h(...this.before)+this.leading.toString()+this.list.map(e=>e.toString()).join("")+h(...this.after)}hasLeadingSpace(){return this.before.length?m(this.before[0]):this.leading.hasLeadingSpace()}indexOf(e){return e===this.leading?"leading":e.type===O.MediaOr?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(t,i){let a;if(i&&(a={...i}),!1===t({node:this.leading,parent:this,state:a},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(t,a))return!1;if(0===this.list.length)return;const n=e(this.list);let r=0;for(;re.toJSON()),before:this.before,after:this.after}}isMediaConditionListWithOr(){return MediaConditionListWithOr.isMediaConditionListWithOr(this)}static isMediaConditionListWithOr(e){return!!e&&(e instanceof MediaConditionListWithOr&&e.type===O.MediaConditionListWithOr)}}function isNumber(e){return!!(t(e)&&M(e.value)||i(e)&&T.has(e.getName().toLowerCase()))}const T=new Set(["abs","acos","asin","atan","atan2","calc","calc-mix","clamp","cos","exp","hypot","log","max","min","mod","pow","rem","round","sign","sin","sqrt","tan"]);function isDimension(e){return t(e)&&p(e.value)}function isIdent(e){return t(e)&&f(e.value)}function isEnvironmentVariable(e){return i(e)&&"env"===e.getName().toLowerCase()}class MediaFeatureName{type=O.MediaFeatureName;name;before;after;constructor(e,t=[],i=[]){this.name=e,this.before=t,this.after=i}getName(){return this.name.value[4].value}getNameToken(){return this.name.value}tokens(){return[...this.before,...this.name.tokens(),...this.after]}toString(){return h(...this.before)+this.name.toString()+h(...this.after)}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens()}}isMediaFeatureName(){return MediaFeatureName.isMediaFeatureName(this)}static isMediaFeatureName(e){return!!e&&(e instanceof MediaFeatureName&&e.type===O.MediaFeatureName)}}function parseMediaFeatureName(e){let t=-1;for(let i=0;ie.tokens()),e.slice(t+1).flatMap(e=>e.tokens()))}class MediaFeatureBoolean{type=O.MediaFeatureBoolean;name;constructor(e){this.name=e}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return this.name.tokens()}toString(){return this.name.toString()}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.name.toJSON(),tokens:this.tokens()}}isMediaFeatureBoolean(){return MediaFeatureBoolean.isMediaFeatureBoolean(this)}static isMediaFeatureBoolean(e){return!!e&&(e instanceof MediaFeatureBoolean&&e.type===O.MediaFeatureBoolean)}}function parseMediaFeatureBoolean(e){const t=parseMediaFeatureName(e);return!1===t?t:new MediaFeatureBoolean(t)}class MediaFeatureValue{type=O.MediaFeatureValue;value;before;after;constructor(e,t=[],i=[]){Array.isArray(e)&&1===e.length?this.value=e[0]:this.value=e,this.before=t,this.after=i}tokens(){return Array.isArray(this.value)?[...this.before,...this.value.flatMap(e=>e.tokens()),...this.after]:[...this.before,...this.value.tokens(),...this.after]}toString(){return Array.isArray(this.value)?h(...this.before)+this.value.map(e=>e.toString()).join("")+h(...this.after):h(...this.before)+this.value.toString()+h(...this.after)}indexOf(e){return e===this.value?"value":-1}at(e){return"value"===e?this.value:Array.isArray(this.value)&&"number"==typeof e?(e<0&&(e=this.value.length+e),this.value[e]):void 0}walk(t,i){if(Array.isArray(this.value)){if(0===this.value.length)return;const a=e(this.value);let n=0;for(;ne.toJSON()),tokens:this.tokens()}:{type:this.type,value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureValue(){return MediaFeatureValue.isMediaFeatureValue(this)}static isMediaFeatureValue(e){return!!e&&(e instanceof MediaFeatureValue&&e.type===O.MediaFeatureValue)}}function parseMediaFeatureValue(e,t=!1){let i=-1,n=-1;for(let r=0;re.tokens()),e.slice(n+1).flatMap(e=>e.tokens()))}function matchesRatioExactly(e){const t=matchesRatio(e);if(-1===t)return-1;const i=t[0],a=t[1];for(let t=a+1;t",e.GT_OR_EQ=">="}(C||(C={})),function(e){e.EQ="="}(Q||(Q={}));class MediaFeatureRangeNameValue{type=O.MediaFeatureRangeNameValue;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.name.tokens(),...this.operator,...this.value.tokens()]}toString(){return this.name.toString()+h(...this.operator)+this.value.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeNameValue(){return MediaFeatureRangeNameValue.isMediaFeatureRangeNameValue(this)}static isMediaFeatureRangeNameValue(e){return!!e&&(e instanceof MediaFeatureRangeNameValue&&e.type===O.MediaFeatureRangeNameValue)}}class MediaFeatureRangeValueName{type=O.MediaFeatureRangeValueName;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.value.tokens(),...this.operator,...this.name.tokens()]}toString(){return this.value.toString()+h(...this.operator)+this.name.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueName(){return MediaFeatureRangeValueName.isMediaFeatureRangeValueName(this)}static isMediaFeatureRangeValueName(e){return!!e&&(e instanceof MediaFeatureRangeValueName&&e.type===O.MediaFeatureRangeValueName)}}class MediaFeatureRangeValueNameValue{type=O.MediaFeatureRangeValueNameValue;name;valueOne;valueOneOperator;valueTwo;valueTwoOperator;constructor(e,t,i,a,n){this.name=e,this.valueOne=t,this.valueOneOperator=i,this.valueTwo=a,this.valueTwoOperator=n}valueOneOperatorKind(){return comparisonFromTokens(this.valueOneOperator)}valueTwoOperatorKind(){return comparisonFromTokens(this.valueTwoOperator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.valueOne.tokens(),...this.valueOneOperator,...this.name.tokens(),...this.valueTwoOperator,...this.valueTwo.tokens()]}toString(){return this.valueOne.toString()+h(...this.valueOneOperator)+this.name.toString()+h(...this.valueTwoOperator)+this.valueTwo.toString()}indexOf(e){return e===this.name?"name":e===this.valueOne?"valueOne":e===this.valueTwo?"valueTwo":-1}at(e){return"name"===e?this.name:"valueOne"===e?this.valueOne:"valueTwo"===e?this.valueTwo:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.valueOne,parent:this,state:i},"valueOne")&&((!("walk"in this.valueOne)||!1!==this.valueOne.walk(e,i))&&(t&&(i={...t}),!1!==e({node:this.valueTwo,parent:this,state:i},"valueTwo")&&((!("walk"in this.valueTwo)||!1!==this.valueTwo.walk(e,i))&&void 0)))}toJSON(){return{type:this.type,name:this.name.toJSON(),valueOne:this.valueOne.toJSON(),valueTwo:this.valueTwo.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueNameValue(){return MediaFeatureRangeValueNameValue.isMediaFeatureRangeValueNameValue(this)}static isMediaFeatureRangeValueNameValue(e){return!!e&&(e instanceof MediaFeatureRangeValueNameValue&&e.type===O.MediaFeatureRangeValueNameValue)}}function parseMediaFeatureRange(e){let t=!1,i=!1;for(let n=0;ne.tokens()),-1!==a&&(s=e.slice(i+1,a+1).flatMap(e=>e.tokens()))):-1!==a&&(s=e.slice(0,a+1).flatMap(e=>e.tokens()));const d=parseMediaConditionWithoutOr(e.slice(Math.max(i,a,n)+1));return!1===d?new MediaQueryWithType(r,[...s,...e.slice(a+1).flatMap(e=>e.tokens())]):new MediaQueryWithType(r,s,e.slice(a+1,n+1).flatMap(e=>e.tokens()),d)}}function parseMediaConditionListWithOr(e){let t=!1;const i=[];let n=-1,r=-1;for(let s=0;se.tokens()),e.slice(r+1).flatMap(e=>e.tokens()))}function parseMediaConditionListWithAnd(e){let t=!1;const i=[];let n=-1,r=-1;for(let s=0;se.tokens()),e.slice(r+1).flatMap(e=>e.tokens()))}function parseMediaCondition(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaConditionListWithOr(e);if(!1!==a)return new MediaCondition(a);const n=parseMediaInParens(e);return!1!==n&&new MediaCondition(n)}function parseMediaConditionWithoutOr(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaConditionListWithAnd(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaInParens(e);return!1!==a&&new MediaCondition(a)}function parseMediaInParens(e){let t=-1;for(let i=0;ie.tokens()),i.startToken],r=[i.endToken,...e.slice(t+1).flatMap(e=>e.tokens())],s=parseMediaFeature(i,n,r);if(!1!==s)return new MediaInParens(s);const o=parseMediaCondition(i.value);return!1!==o?new MediaInParens(o,n,r):new MediaInParens(new GeneralEnclosed(i),e.slice(0,t).flatMap(e=>e.tokens()),e.slice(t+1).flatMap(e=>e.tokens()))}function parseMediaInParensFromSimpleBlock(e){if(!k(e.startToken))return!1;const t=parseMediaFeature(e,[e.startToken],[e.endToken]);if(!1!==t)return new MediaInParens(t);const i=parseMediaCondition(e.value);return!1!==i?new MediaInParens(i,[e.startToken],[e.endToken]):new MediaInParens(new GeneralEnclosed(e))}!function(e){e.Not="not",e.Only="only"}(W||(W={}));const V=/^not$/i;function parseMediaNot(e){let t=!1,i=null;for(let n=0;ne.tokens()),t);continue}return!1}}return i||!1}const L=/^or$/i;function parseMediaOr(e){let t=!1;for(let i=0;ie.tokens()),t)}}return!1}}return!1}const R=/^and$/i;function parseMediaAnd(e){let t=!1;for(let i=0;ie.tokens()),t)}}return!1}}return!1}function parseFromTokens(e,t){const i=l(e,{onParseError:t?.onParseError});return i.map((e,a)=>{const n=parseMediaQuery(e);return!1===n&&!0===t?.preserveInvalidMediaQueries?new MediaQueryInvalid(i[a]):n}).filter(e=>!!e)}function parse(e,t){return parseFromTokens(F({css:e},{onParseError:t?.onParseError}),t)}class CustomMedia{type=O.CustomMedia;name;mediaQueryList=null;trueOrFalseKeyword=null;constructor(e,t,i){this.name=e,this.mediaQueryList=t,this.trueOrFalseKeyword=i??null}getName(){for(let e=0;ee.toJSON())}}isCustomMedia(){return CustomMedia.isCustomMedia(this)}static isCustomMedia(e){return!!e&&(e instanceof CustomMedia&&e.type===O.CustomMedia)}}function parseCustomMediaFromTokens(e,t){let i=[],a=e;for(let t=0;te.tokens())}toString(){return this.media.map(e=>e.toString()).join("")}walk(t,i){if(0===this.media.length)return;const a=e(this.media);let n=0;for(;ne.tokens()),...this.after]}toString(){return h(...this.before)+this.leading.toString()+this.list.map(e=>e.toString()).join("")+h(...this.after)}hasLeadingSpace(){return this.before.length?m(this.before[0]):this.leading.hasLeadingSpace()}indexOf(e){return e===this.leading?"leading":e.type===T.MediaAnd?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(t,i){let a;if(i&&(a={...i}),!1===t({node:this.leading,parent:this,state:a},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(t,a))return!1;if(0===this.list.length)return;const n=e(this.list);let r=0;for(;re.toJSON()),before:this.before,after:this.after}}isMediaConditionListWithAnd(){return MediaConditionListWithAnd.isMediaConditionListWithAnd(this)}static isMediaConditionListWithAnd(e){return!!e&&(e instanceof MediaConditionListWithAnd&&e.type===T.MediaConditionListWithAnd)}}class MediaConditionListWithOr{type=T.MediaConditionListWithOr;leading;list;before;after;constructor(e,t,i=[],a=[]){this.leading=e,this.list=t,this.before=i,this.after=a}tokens(){return[...this.before,...this.leading.tokens(),...this.list.flatMap(e=>e.tokens()),...this.after]}toString(){return h(...this.before)+this.leading.toString()+this.list.map(e=>e.toString()).join("")+h(...this.after)}hasLeadingSpace(){return this.before.length?m(this.before[0]):this.leading.hasLeadingSpace()}indexOf(e){return e===this.leading?"leading":e.type===T.MediaOr?this.list.indexOf(e):-1}at(e){return"leading"===e?this.leading:"number"==typeof e?(e<0&&(e=this.list.length+e),this.list[e]):void 0}walk(t,i){let a;if(i&&(a={...i}),!1===t({node:this.leading,parent:this,state:a},"leading"))return!1;if("walk"in this.leading&&!1===this.leading.walk(t,a))return!1;if(0===this.list.length)return;const n=e(this.list);let r=0;for(;re.toJSON()),before:this.before,after:this.after}}isMediaConditionListWithOr(){return MediaConditionListWithOr.isMediaConditionListWithOr(this)}static isMediaConditionListWithOr(e){return!!e&&(e instanceof MediaConditionListWithOr&&e.type===T.MediaConditionListWithOr)}}function isNumber(e){return!!(t(e)&&M(e.value)||i(e)&&O.has(e.getName().toLowerCase()))}const O=new Set(["abs","acos","asin","atan","atan2","calc","calc-mix","clamp","cos","exp","hypot","log","max","min","mod","pow","rem","round","sign","sin","sqrt","tan"]);function isDimension(e){return t(e)&&p(e.value)}function isIdent(e){return t(e)&&f(e.value)}function isEnvironmentVariable(e){return i(e)&&"env"===e.getName().toLowerCase()}class MediaFeatureName{type=T.MediaFeatureName;name;before;after;constructor(e,t=[],i=[]){this.name=e,this.before=t,this.after=i}getName(){return this.name.value[4].value}getNameToken(){return this.name.value}tokens(){return[...this.before,...this.name.tokens(),...this.after]}toString(){return h(...this.before)+this.name.toString()+h(...this.after)}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.getName(),tokens:this.tokens()}}isMediaFeatureName(){return MediaFeatureName.isMediaFeatureName(this)}static isMediaFeatureName(e){return!!e&&(e instanceof MediaFeatureName&&e.type===T.MediaFeatureName)}}function parseMediaFeatureName(e){let t=-1;for(let i=0;ie.tokens()),e.slice(t+1).flatMap(e=>e.tokens()))}class MediaFeatureBoolean{type=T.MediaFeatureBoolean;name;constructor(e){this.name=e}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return this.name.tokens()}toString(){return this.name.toString()}indexOf(e){return e===this.name?"name":-1}at(e){if("name"===e)return this.name}toJSON(){return{type:this.type,name:this.name.toJSON(),tokens:this.tokens()}}isMediaFeatureBoolean(){return MediaFeatureBoolean.isMediaFeatureBoolean(this)}static isMediaFeatureBoolean(e){return!!e&&(e instanceof MediaFeatureBoolean&&e.type===T.MediaFeatureBoolean)}}function parseMediaFeatureBoolean(e){const t=parseMediaFeatureName(e);return!1===t?t:new MediaFeatureBoolean(t)}class MediaFeatureValue{type=T.MediaFeatureValue;value;before;after;constructor(e,t=[],i=[]){Array.isArray(e)&&1===e.length?this.value=e[0]:this.value=e,this.before=t,this.after=i}tokens(){return Array.isArray(this.value)?[...this.before,...this.value.flatMap(e=>e.tokens()),...this.after]:[...this.before,...this.value.tokens(),...this.after]}toString(){return Array.isArray(this.value)?h(...this.before)+this.value.map(e=>e.toString()).join("")+h(...this.after):h(...this.before)+this.value.toString()+h(...this.after)}indexOf(e){return e===this.value?"value":-1}at(e){return"value"===e?this.value:Array.isArray(this.value)&&"number"==typeof e?(e<0&&(e=this.value.length+e),this.value[e]):void 0}walk(t,i){if(Array.isArray(this.value)){if(0===this.value.length)return;const a=e(this.value);let n=0;for(;ne.toJSON()),tokens:this.tokens()}:{type:this.type,value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureValue(){return MediaFeatureValue.isMediaFeatureValue(this)}static isMediaFeatureValue(e){return!!e&&(e instanceof MediaFeatureValue&&e.type===T.MediaFeatureValue)}}function parseMediaFeatureValue(e,t=!1){let i=-1,n=-1;for(let r=0;re.tokens()),e.slice(n+1).flatMap(e=>e.tokens()))}function matchesRatioExactly(e){const t=matchesRatio(e);if(-1===t)return-1;const i=t[0],a=t[1];for(let t=a+1;t",e.GT_OR_EQ=">="}(C||(C={})),function(e){e.EQ="="}(Q||(Q={}));class MediaFeatureRangeNameValue{type=T.MediaFeatureRangeNameValue;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.name.tokens(),...this.operator,...this.value.tokens()]}toString(){return this.name.toString()+h(...this.operator)+this.value.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeNameValue(){return MediaFeatureRangeNameValue.isMediaFeatureRangeNameValue(this)}static isMediaFeatureRangeNameValue(e){return!!e&&(e instanceof MediaFeatureRangeNameValue&&e.type===T.MediaFeatureRangeNameValue)}}class MediaFeatureRangeValueName{type=T.MediaFeatureRangeValueName;name;operator;value;constructor(e,t,i){this.name=e,this.operator=t,this.value=i}operatorKind(){return comparisonFromTokens(this.operator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.value.tokens(),...this.operator,...this.name.tokens()]}toString(){return this.value.toString()+h(...this.operator)+this.name.toString()}indexOf(e){return e===this.name?"name":e===this.value?"value":-1}at(e){return"name"===e?this.name:"value"===e?this.value:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.value,parent:this,state:i},"value")&&("walk"in this.value?this.value.walk(e,i):void 0)}toJSON(){return{type:this.type,name:this.name.toJSON(),value:this.value.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueName(){return MediaFeatureRangeValueName.isMediaFeatureRangeValueName(this)}static isMediaFeatureRangeValueName(e){return!!e&&(e instanceof MediaFeatureRangeValueName&&e.type===T.MediaFeatureRangeValueName)}}class MediaFeatureRangeValueNameValue{type=T.MediaFeatureRangeValueNameValue;name;valueOne;valueOneOperator;valueTwo;valueTwoOperator;constructor(e,t,i,a,n){this.name=e,this.valueOne=t,this.valueOneOperator=i,this.valueTwo=a,this.valueTwoOperator=n}valueOneOperatorKind(){return comparisonFromTokens(this.valueOneOperator)}valueTwoOperatorKind(){return comparisonFromTokens(this.valueTwoOperator)}getName(){return this.name.getName()}getNameToken(){return this.name.getNameToken()}tokens(){return[...this.valueOne.tokens(),...this.valueOneOperator,...this.name.tokens(),...this.valueTwoOperator,...this.valueTwo.tokens()]}toString(){return this.valueOne.toString()+h(...this.valueOneOperator)+this.name.toString()+h(...this.valueTwoOperator)+this.valueTwo.toString()}indexOf(e){return e===this.name?"name":e===this.valueOne?"valueOne":e===this.valueTwo?"valueTwo":-1}at(e){return"name"===e?this.name:"valueOne"===e?this.valueOne:"valueTwo"===e?this.valueTwo:void 0}walk(e,t){let i;return t&&(i={...t}),!1!==e({node:this.valueOne,parent:this,state:i},"valueOne")&&((!("walk"in this.valueOne)||!1!==this.valueOne.walk(e,i))&&(t&&(i={...t}),!1!==e({node:this.valueTwo,parent:this,state:i},"valueTwo")&&((!("walk"in this.valueTwo)||!1!==this.valueTwo.walk(e,i))&&void 0)))}toJSON(){return{type:this.type,name:this.name.toJSON(),valueOne:this.valueOne.toJSON(),valueTwo:this.valueTwo.toJSON(),tokens:this.tokens()}}isMediaFeatureRangeValueNameValue(){return MediaFeatureRangeValueNameValue.isMediaFeatureRangeValueNameValue(this)}static isMediaFeatureRangeValueNameValue(e){return!!e&&(e instanceof MediaFeatureRangeValueNameValue&&e.type===T.MediaFeatureRangeValueNameValue)}}function parseMediaFeatureRange(e){let t=!1,i=!1;for(let n=0;ne.tokens()),-1!==a&&(s=e.slice(i+1,a+1).flatMap(e=>e.tokens()))):-1!==a&&(s=e.slice(0,a+1).flatMap(e=>e.tokens()));const d=parseMediaConditionWithoutOr(e.slice(Math.max(i,a,n)+1));return!1===d?new MediaQueryWithType(r,[...s,...e.slice(a+1).flatMap(e=>e.tokens())]):new MediaQueryWithType(r,s,e.slice(a+1,n+1).flatMap(e=>e.tokens()),d)}}function parseMediaConditionList(e,t){let i=!1,n=!1;const r=[];let s=-1,o=-1;for(let u=0;ue.tokens()),a=e.slice(o+1).flatMap(e=>e.tokens());return"and"===n?new MediaConditionListWithAnd(i,r,t,a):new MediaConditionListWithOr(i,r,t,a)}return!1}function parseMediaCondition(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaInParens(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaConditionList(e,!0);return!1!==a&&new MediaCondition(a)}function parseMediaConditionWithoutOr(e){const t=parseMediaNot(e);if(!1!==t)return new MediaCondition(t);const i=parseMediaInParens(e);if(!1!==i)return new MediaCondition(i);const a=parseMediaConditionList(e,!1);return!1!==a&&new MediaCondition(a)}function parseMediaInParens(e){let t=-1;for(let i=0;ie.tokens()),i.startToken],r=[i.endToken,...e.slice(t+1).flatMap(e=>e.tokens())],s=parseMediaFeature(i,n,r);if(!1!==s)return new MediaInParens(s);const o=parseMediaCondition(i.value);return!1!==o?new MediaInParens(o,n,r):new MediaInParens(new GeneralEnclosed(i),e.slice(0,t).flatMap(e=>e.tokens()),e.slice(t+1).flatMap(e=>e.tokens()))}function parseMediaInParensFromSimpleBlock(e){if(!k(e.startToken))return!1;const t=parseMediaFeature(e,[e.startToken],[e.endToken]);if(!1!==t)return new MediaInParens(t);const i=parseMediaCondition(e.value);return!1!==i?new MediaInParens(i,[e.startToken],[e.endToken]):new MediaInParens(new GeneralEnclosed(e))}!function(e){e.Not="not",e.Only="only"}(W||(W={}));const V=/^not$/i;function parseMediaNot(e){let t=!1,i=null;for(let n=0;ne.tokens()),t);continue}return!1}}return i||!1}const L=/^or$/i;function parseMediaOr(e){let t=!1;for(let i=0;ie.tokens()),t)}}return!1}}return!1}const R=/^and$/i;function parseMediaAnd(e){let t=!1;for(let i=0;ie.tokens()),t)}}return!1}}return!1}function parseFromTokens(e,t){const i=l(e,{onParseError:t?.onParseError});return i.map((e,a)=>{const n=parseMediaQuery(e);return!1===n&&!0===t?.preserveInvalidMediaQueries?new MediaQueryInvalid(i[a]):n}).filter(e=>!!e)}function parse(e,t){return parseFromTokens(F({css:e},{onParseError:t?.onParseError}),t)}class CustomMedia{type=T.CustomMedia;name;mediaQueryList=null;trueOrFalseKeyword=null;constructor(e,t,i){this.name=e,this.mediaQueryList=t,this.trueOrFalseKeyword=i??null}getName(){for(let e=0;ee.toJSON())}}isCustomMedia(){return CustomMedia.isCustomMedia(this)}static isCustomMedia(e){return!!e&&(e instanceof CustomMedia&&e.type===T.CustomMedia)}}function parseCustomMediaFromTokens(e,t){let i=[],a=e;for(let t=0;t): MediaQu } } -function parseMediaConditionListWithOr(componentValues: Array): MediaConditionListWithOr | false { +function parseMediaConditionList(componentValues: Array, allowOr: boolean): MediaConditionListWithAnd | MediaConditionListWithOr | false { let leading: MediaInParens | false = false; - const list: Array = []; + let operator: 'and' | 'or' | false = false; + const list: Array = []; let firstIndex = -1; let lastIndex = -1; for (let i = 0; i < componentValues.length; i++) { - if (leading) { - const part = parseMediaOr(componentValues.slice(i)); - if (part !== false) { - i += part.advance; - list.push(part.node); + if (leading && operator === false) { + const mediaAnd = parseMediaAnd(componentValues.slice(i)); + if (mediaAnd !== false) { + operator = 'and'; + i += mediaAnd.advance; + list.push(mediaAnd.node); lastIndex = i; continue; } - } - - const componentValue = componentValues[i]; - if (componentValue.type === ComponentValueType.Whitespace) { - continue; - } - - if (componentValue.type === ComponentValueType.Comment) { - continue; - } - - if (leading) { - return false; - } - if (leading === false && isSimpleBlockNode(componentValue)) { - componentValue.normalize(); - leading = parseMediaInParensFromSimpleBlock(componentValue); - if (leading === false) { - return false; + if (allowOr) { + const mediaOr = parseMediaOr(componentValues.slice(i)); + if (mediaOr !== false) { + operator = 'or'; + i += mediaOr.advance; + list.push(mediaOr.node); + lastIndex = i; + continue; + } } - - firstIndex = i; - continue; } - return false; - } - - if (leading && list.length) { - return new MediaConditionListWithOr( - leading, - list, - componentValues.slice(0, firstIndex).flatMap((x) => { - return x.tokens(); - }), - componentValues.slice(lastIndex + 1).flatMap((x) => { - return x.tokens(); - }), - ); - } - - return false; -} - -function parseMediaConditionListWithAnd(componentValues: Array): MediaConditionListWithAnd | false { - let leading: MediaInParens | false = false; - const list: Array = []; - let firstIndex = -1; - let lastIndex = -1; - - for (let i = 0; i < componentValues.length; i++) { - if (leading) { - const part = parseMediaAnd(componentValues.slice(i)); + if (leading && operator) { + const part = operator === 'and' ? parseMediaAnd(componentValues.slice(i)) : parseMediaOr(componentValues.slice(i)); if (part !== false) { i += part.advance; list.push(part.node); @@ -202,7 +165,7 @@ function parseMediaConditionListWithAnd(componentValues: Array): return false; } - if (leading === false && isSimpleBlockNode(componentValue)) { + if (isSimpleBlockNode(componentValue)) { componentValue.normalize(); leading = parseMediaInParensFromSimpleBlock(componentValue); if (leading === false) { @@ -217,16 +180,18 @@ function parseMediaConditionListWithAnd(componentValues: Array): } if (leading && list.length) { - return new MediaConditionListWithAnd( - leading, - list, - componentValues.slice(0, firstIndex).flatMap((x) => { - return x.tokens(); - }), - componentValues.slice(lastIndex + 1).flatMap((x) => { - return x.tokens(); - }), - ); + const before = componentValues.slice(0, firstIndex).flatMap((x) => { + return x.tokens(); + }); + const after = componentValues.slice(lastIndex + 1).flatMap((x) => { + return x.tokens(); + }); + + if (operator === 'and') { + return new MediaConditionListWithAnd(leading, list as Array, before, after); + } + + return new MediaConditionListWithOr(leading, list as Array, before, after); } return false; @@ -238,21 +203,16 @@ function parseMediaCondition(componentValues: Array): MediaCondi return new MediaCondition(mediaNot); } - const mediaListAnd = parseMediaConditionListWithAnd(componentValues); - if (mediaListAnd !== false) { - return new MediaCondition(mediaListAnd); - } - - const mediaListOr = parseMediaConditionListWithOr(componentValues); - if (mediaListOr !== false) { - return new MediaCondition(mediaListOr); - } - const mediaInParens = parseMediaInParens(componentValues); if (mediaInParens !== false) { return new MediaCondition(mediaInParens); } + const mediaConditionList = parseMediaConditionList(componentValues, true); + if (mediaConditionList !== false) { + return new MediaCondition(mediaConditionList); + } + return false; } @@ -262,16 +222,16 @@ function parseMediaConditionWithoutOr(componentValues: Array): M return new MediaCondition(mediaNot); } - const mediaListAnd = parseMediaConditionListWithAnd(componentValues); - if (mediaListAnd !== false) { - return new MediaCondition(mediaListAnd); - } - const mediaInParens = parseMediaInParens(componentValues); if (mediaInParens !== false) { return new MediaCondition(mediaInParens); } + const mediaConditionList = parseMediaConditionList(componentValues, false); + if (mediaConditionList !== false) { + return new MediaCondition(mediaConditionList); + } + return false; } diff --git a/packages/media-query-list-parser/test/api/deeply-nested.mjs b/packages/media-query-list-parser/test/api/deeply-nested.mjs new file mode 100644 index 0000000000..46e3d2de4f --- /dev/null +++ b/packages/media-query-list-parser/test/api/deeply-nested.mjs @@ -0,0 +1,24 @@ +import assert from 'node:assert'; +import { performance } from 'node:perf_hooks'; +import { parse } from '@csstools/media-query-list-parser'; + +{ + const depth = 500; + const source = '('.repeat(depth) + 'width' + ')'.repeat(depth); + + const start = performance.now(); + const resultAST = parse(source); + const duration = performance.now() - start; + + assert.equal(resultAST.length, 1); + + assert.equal( + resultAST[0].toString(), + source, + ); + + assert.ok( + duration < 1000, + `Parsing a deeply nested media query took ${duration}ms, expected well under 1000ms.`, + ); +} diff --git a/packages/media-query-list-parser/test/test.mjs b/packages/media-query-list-parser/test/test.mjs index f487bde2ab..720484c579 100644 --- a/packages/media-query-list-parser/test/test.mjs +++ b/packages/media-query-list-parser/test/test.mjs @@ -1,3 +1,4 @@ +import './api/deeply-nested.mjs'; import './api/options.mjs'; import './cases/custom-media/0001.mjs';