/**
 * The `RulesetContainer` module contains classes used to track declaration concerns and
 * explicit resolutions associated with a `Style` object.
 *
 * Every `Style` object has a `RulesetContainer`. A `Style` object's behavior may be defined
 * by multiple rulesets, and may have multiple stylable targets (ex: `::self`, `::before`,
 * `::after`). Every ruleset may provide resolution guidance against another `Style` object.
 */ import { MultiMap , TwoKeyMultiMap } from "@opticss/util" ; import { ParsedSelector , postcss } from "opticss" ; import { BLOCK_PROP_NAMES , SELF_SELECTOR , getResolution } from "../BlockSyntax" ; import { Configuration } from "../configuration" ; import { InvalidBlockSyntax } from "../errors" ; import { sourceRange } from "../SourceLocation" ; import { expandProp } from "../util/propertyParser" ; import { Styles , isStyle } from "./Styles" ; export { Styles , BlockClass , AttrValue } from "./Styles" ; export type Pseudo = string ; export type Property = string ; export type Declaration = { node : postcss . Declaration ; value : string ; } ; export type Resolution < S extends Styles = Styles > = { node : postcss . Rule ; property : string ; resolution : S ; } ; /**
 * Represents an individual ruleset, its property concerns, and Style resolutions.
 */ export class Ruleset < Style extends Styles = Styles > { file : string ; node : postcss . Rule ; style : Style ; declarations = new MultiMap < Property , Declaration > ( ) ; resolutions = new MultiMap < Property , Styles > ( ) ; constructor ( file , node , style ) { this . file = file ; this . node = node ; this . style = style ; } param property param style addResolution ( property , style ) { let expanded = expandProp ( property , "inherit" ) ; for ( let prop of Object . keys ( expanded ) ) { this . resolutions . set ( prop , style ) ; } } param property param style hasResolutionFor ( property , other ) { return this . resolutions . hasValue ( property , other ) ; } } /**
 * Cache and interface methods for all rulesets that may apply to a Style.
 */ export class RulesetContainer < S extends Styles > { private parent : S ; private rules : MultiMap < Pseudo , Ruleset < S > > = new MultiMap ( false ) ; private concerns : TwoKeyMultiMap < Pseudo , Property , Ruleset < S > > = new TwoKeyMultiMap ( false ) ; constructor ( parent ) { this . parent = parent ; } param rule param block addRuleset ( configuration , file , rule ) { let style = this . parent ; let selectors = style . getParsedSelectors ( rule ) ; selectors . forEach ( ( selector ) => { let ruleSet = new Ruleset ( file , rule , style ) ; let key = selector . key ; let pseudo = key . pseudoelement ? key . pseudoelement . toString ( ) : SELF_SELECTOR ; rule . walkDecls ( ( decl ) => { if ( BLOCK_PROP_NAMES . has ( decl . prop ) ) { return ; } let resolution = getResolution ( decl . value ) ; if ( resolution . path ) { let errLoc = sourceRange ( configuration , style . block . stylesheet , file , decl ) ; let other = style . block . lookup ( resolution . path , errLoc ) ; if ( other && other . block === style . block ) { throw new InvalidBlockSyntax ( `Cannot resolve conflicts with your own block.` , errLoc ) ; } if ( other && other . block . isAncestorOf ( style . block ) ) { throw new InvalidBlockSyntax ( `Cannot resolve conflicts with ancestors of your own block.` , errLoc ) ; } if ( isStyle ( other ) ) { ruleSet . addResolution ( decl . prop , other ) ; } } else { let expanded = expandProp ( decl . prop , decl . value ) ; for ( let prop in expanded ) { let value = expanded [ prop ] ; ruleSet . declarations . set ( prop , { node : decl , value } ) ; this . concerns . set ( pseudo , prop , ruleSet ) ; } } } ) ; } ) ; } param pseudo returns getRulesets ( prop ? , pseudo ? ) { let res = [ ] ; let pseudos = pseudo ? [ pseudo ] : this . getPseudos ( ) ; if ( ! prop ) { for ( let pseudo of pseudos ) { res = [ ... res , ... this . rules . get ( pseudo ) ] ; } return new Set ( res ) ; } for ( let pseudo of pseudos ) { res = [ ... res , ... this . concerns . get ( pseudo , prop ) ] ; } return new Set ( res ) ; } param pseudo returns getProperties ( pseudo = SELF_SELECTOR ) { if ( ! pseudo ) { let res = [ ] ; for ( let pseudo of this . getPseudos ( ) ) { res = [ ... res , ... this . getProperties ( pseudo ) ] ; } return new Set ( res ) ; } return new Set ( [ ... this . concerns . subKeys ( pseudo ) ] ) ; } returns getPseudos ( ) { return new Set ( [ ... this . concerns . primaryKeys ( ) ] ) ; } returns * getAllResolutions ( ) { let ruleSets = this . rules . individualValues ( ) ; for ( let rule of ruleSets ) { for ( let [ property , styles ] of rule . resolutions ) { for ( let style of styles ) { yield { node : rule . node , property , resolution : style , } ; } } } } }