| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -138,8 +138,9 @@ function apply_selector(stylesheet: Stylesheet, blocks: Block[], node: Node, sta
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						while (i--) {
 | 
					 | 
					 | 
					 | 
						while (i--) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							const selector = block.selectors[i];
 | 
					 | 
					 | 
					 | 
							const selector = block.selectors[i];
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							const name = typeof selector.name === 'string' && selector.name.replace(/\\(.)/g, '$1');
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (selector.type === 'PseudoClassSelector' && selector.name === 'global') {
 | 
					 | 
					 | 
					 | 
							if (selector.type === 'PseudoClassSelector' && name === 'global') {
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								// TODO shouldn't see this here... maybe we should enforce that :global(...)
 | 
					 | 
					 | 
					 | 
								// TODO shouldn't see this here... maybe we should enforce that :global(...)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								// cannot be sandwiched between non-global selectors?
 | 
					 | 
					 | 
					 | 
								// cannot be sandwiched between non-global selectors?
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								return false;
 | 
					 | 
					 | 
					 | 
								return false;
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -150,11 +151,11 @@ function apply_selector(stylesheet: Stylesheet, blocks: Block[], node: Node, sta
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (selector.type === 'ClassSelector') {
 | 
					 | 
					 | 
					 | 
							if (selector.type === 'ClassSelector') {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (!attribute_matches(node, 'class', selector.name, '~=', false) && !class_matches(node, selector.name)) return false;
 | 
					 | 
					 | 
					 | 
								if (!attribute_matches(node, 'class', name, '~=', false) && !node.classes.some(c => c.name === name)) return false;
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							else if (selector.type === 'IdSelector') {
 | 
					 | 
					 | 
					 | 
							else if (selector.type === 'IdSelector') {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (!attribute_matches(node, 'id', selector.name, '=', false)) return false;
 | 
					 | 
					 | 
					 | 
								if (!attribute_matches(node, 'id', name, '=', false)) return false;
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							else if (selector.type === 'AttributeSelector') {
 | 
					 | 
					 | 
					 | 
							else if (selector.type === 'AttributeSelector') {
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -162,8 +163,7 @@ function apply_selector(stylesheet: Stylesheet, blocks: Block[], node: Node, sta
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							else if (selector.type === 'TypeSelector') {
 | 
					 | 
					 | 
					 | 
							else if (selector.type === 'TypeSelector') {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								// remove toLowerCase() in v2, when uppercase elements will be forbidden
 | 
					 | 
					 | 
					 | 
								if (node.name.toLowerCase() !== name.toLowerCase() && name !== '*') return false;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
								if (node.name.toLowerCase() !== selector.name.toLowerCase() && selector.name !== '*') return false;
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							}
 | 
					 | 
					 | 
					 | 
							}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							else {
 | 
					 | 
					 | 
					 | 
							else {
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -206,14 +206,21 @@ function apply_selector(stylesheet: Stylesheet, blocks: Block[], node: Node, sta
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return true;
 | 
					 | 
					 | 
					 | 
						return true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					const operators = {
 | 
					 | 
					 | 
					 | 
					function test_attribute(operator, expected_value, case_insensitive, value) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						'=' : (value: string, flags: string) => new RegExp(`^${value}$`, flags),
 | 
					 | 
					 | 
					 | 
						if (case_insensitive) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						'~=': (value: string, flags: string) => new RegExp(`\\b${value}\\b`, flags),
 | 
					 | 
					 | 
					 | 
							expected_value = expected_value.toLowerCase();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						'|=': (value: string, flags: string) => new RegExp(`^${value}(-.+)?$`, flags),
 | 
					 | 
					 | 
					 | 
							value = value.toLowerCase();
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						'^=': (value: string, flags: string) => new RegExp(`^${value}`, flags),
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						'$=': (value: string, flags: string) => new RegExp(`${value}$`, flags),
 | 
					 | 
					 | 
					 | 
						switch (operator) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						'*=': (value: string, flags: string) => new RegExp(value, flags)
 | 
					 | 
					 | 
					 | 
							case '=': return value === expected_value;
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					};
 | 
					 | 
					 | 
					 | 
							case '~=': return ` ${value} `.includes(` ${expected_value} `);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							case '|=': return `${value}-`.startsWith(`${expected_value}-`);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							case '^=': return value.startsWith(expected_value);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							case '$=': return value.endsWith(expected_value);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							case '*=': return value.includes(expected_value);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
							default: throw new Error(`this shouldn't happen`);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					function attribute_matches(node: Node, name: string, expected_value: string, operator: string, case_insensitive: boolean) {
 | 
					 | 
					 | 
					 | 
					function attribute_matches(node: Node, name: string, expected_value: string, operator: string, case_insensitive: boolean) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						const spread = node.attributes.find(attr => attr.type === 'Spread');
 | 
					 | 
					 | 
					 | 
						const spread = node.attributes.find(attr => attr.type === 'Spread');
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -227,29 +234,22 @@ function attribute_matches(node: Node, name: string, expected_value: string, ope
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (attr.chunks.length > 1) return true;
 | 
					 | 
					 | 
					 | 
						if (attr.chunks.length > 1) return true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (!expected_value) return true;
 | 
					 | 
					 | 
					 | 
						if (!expected_value) return true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						const pattern = operators[operator](expected_value, case_insensitive ? 'i' : '');
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						const value = attr.chunks[0];
 | 
					 | 
					 | 
					 | 
						const value = attr.chunks[0];
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (!value) return false;
 | 
					 | 
					 | 
					 | 
						if (!value) return false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (value.type === 'Text') return pattern.test(value.data);
 | 
					 | 
					 | 
					 | 
						if (value.type === 'Text') return test_attribute(operator, expected_value, case_insensitive, value.data);
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						const possible_values = new Set();
 | 
					 | 
					 | 
					 | 
						const possible_values = new Set();
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						gather_possible_values(value.node, possible_values);
 | 
					 | 
					 | 
					 | 
						gather_possible_values(value.node, possible_values);
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (possible_values.has(UNKNOWN)) return true;
 | 
					 | 
					 | 
					 | 
						if (possible_values.has(UNKNOWN)) return true;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						for (const x of Array.from(possible_values)) { // TypeScript for-of is slightly unlike JS
 | 
					 | 
					 | 
					 | 
						for (const value of possible_values) {
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							if (pattern.test(x)) return true;
 | 
					 | 
					 | 
					 | 
							if (test_attribute(operator, expected_value, case_insensitive, value)) return true;
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						}
 | 
					 | 
					 | 
					 | 
						}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return false;
 | 
					 | 
					 | 
					 | 
						return false;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					}
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					function class_matches(node, name: string) {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						return node.classes.some((class_directive) => {
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
							return new RegExp(`\\b${name}\\b`).test(class_directive.name);
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						});
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					function unquote(value: Node) {
 | 
					 | 
					 | 
					 | 
					function unquote(value: Node) {
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						if (value.type === 'Identifier') return value.name;
 | 
					 | 
					 | 
					 | 
						if (value.type === 'Identifier') return value.name;
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
						const str = value.value;
 | 
					 | 
					 | 
					 | 
						const str = value.value;
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
 
 |