/**
 * The `Inheritable` module delivers the core data structure for making type safe,
 * single-typed-children, tree nodes.
 *
 * This abstract class, in order to support tree nodes of *any* kind, makes creative
 * use of the `any` type in a few places – but don't be fooled! These typing holes
 * are *required* to be plugged by any by any implementing class by virtue of the type
 * generics they are forced to provide when extending. By the time this abstract class
 * is exposed to the outside world, all typing holes have been plugged and we are left
 * with a fully typed tree structure.
 */ import { ObjectDictionary } from "@opticss/util" ; import { ParsedSelector , SelectorFactory , parseSelector , postcss } from "opticss" ; export type AnyNode = Inheritable < any , any , any , any , any > ; export abstract class Inheritable < Self extends Inheritable < Self , Root , Parent , Child , Token > , Root extends Inheritable < any , Root , never , AnyNode , any > , Parent extends Inheritable < any , Root , AnyNode | null , Self , any > | null , Child extends Inheritable < any , Root , Self , AnyNode | never , any > | never , Token extends any = string > implements SelectorFactory { protected abstract get ChildConstructor ( ) : { new ( token , parent ) : Child ; } | never ; private readonly parsedRuleSelectors : WeakMap < postcss . Rule , ParsedSelector [ ] > | null ; protected _token : Token ; protected _base : Self | undefined ; protected _root : Root ; protected _parent : Parent | null ; protected _children : Map < string , Child > = new Map ( ) ; param name param parent constructor ( name , parent ? ) { this . _token = name ; this . _parent = parent || null ; this . _root = parent ? parent . root : this . asRoot ( ) ; this . parsedRuleSelectors = this . isRootNode ? new WeakMap ( ) : null ; } returns protected tokenToUid ( token ) { return String ( token ) ; } param token returns protected newChild ( token ) { return new this . ChildConstructor ( token , this . asSelf ( ) ) ; } param token returns private childToUid ( token ) { return this . ChildConstructor . prototype . tokenToUid ( token ) ; } returns public get token ( ) : Token { return this . _token ; } returns protected get uid ( ) : string { return this . tokenToUid ( this . _token ) ; } returns protected get parent ( ) : Parent { return this . _parent as Parent ; } returns protected get root ( ) : Root { return this . _root ; } returns private get isRootNode ( ) : boolean { return this . _root === this . asRoot ( ) ; } /**
     * Get the style that this style inherits from, if any.
     *
     * This walks down the declared styles of the parent's inheritance chain,
     * and attempts to find a matching directly declared style on each.
     *
     * The result is cached because it never changes and is decidable as soon
     * as the style is instantiated.
     */ public get base ( ) : Self | undefined { if ( this . _base !== undefined || ! this . parent ) { return this . _base || undefined ; } let baseParent = this . parent . base ; while ( baseParent ) { let cls = baseParent ? baseParent . getChild ( this . token ) : undefined ; if ( cls ) { this . _base = cls ; return cls ; } baseParent = baseParent . base ; } return this . _base = undefined ; } returns public get block ( ) : Root { return this . root ; } returns public resolveInheritance ( ) { let inherited = [ ] ; let base = this . base ; while ( base ) { inherited . unshift ( base ) ; base = base . base ; } return inherited ; } param name returns protected resolveChild ( token ) { let child = this . getChild ( token ) ; let container = this . base ; while ( ! child && container ) { child = container . getChild ( token ) ; container = container . base ; } return child || null ; } param key returns protected getChild ( token ) { return this . _children . get ( this . childToUid ( token ) ) || null ; } param key returns protected setChild ( token , value ) { this . _children . set ( this . childToUid ( token ) , value ) ; return value ; } param name param key returns protected ensureChild ( token , key ? ) { key = key !== undefined ? key : this . childToUid ( token ) ; if ( ! this . _children . has ( key ) ) { this . _children . set ( key , this . newChild ( token ) ) ; } return this . _children . get ( key ) ! ; } returns protected children ( ) { return [ ... this . _children . values ( ) ] ; } returns protected resolveChildren ( ) { return [ ... this . resolveChildrenMap ( ) . values ( ) ] ; } returns protected childrenMap ( ) { return new Map ( this . _children ) ; } returns protected resolveChildrenMap ( ) { let inheritance = [ ... this . resolveInheritance ( ) , this . asSelf ( ) ] ; let out = new Map ( ) ; for ( let o of inheritance ) { for ( let [ key , value ] of o . _children . entries ( ) ) { out . set ( key , value ) ; } } return out ; } returns protected childrenHash ( ) { let out = { } ; for ( let [ key , value ] of this . _children ) { out [ key ] = value ; } return out ; } returns protected resolveChildrenHash ( ) { let out = { } ; for ( let [ key , value ] of this . resolveChildrenMap ( ) ) { out [ key ] = value ; } return out ; } param rule return public getParsedSelectors ( rule ) { if ( ! this . isRootNode ) { return this . root . getParsedSelectors ( rule ) ; } let selectors = this . parsedRuleSelectors ! . get ( rule ) ; if ( ! selectors ) { selectors = parseSelector ( rule ) ; this . parsedRuleSelectors ! . set ( rule , selectors ) ; } return selectors ; } /**
     * TypeScript can't figure out that `this` is the `Self` so this private
     * method casts it in a few places where it's needed.
     */ protected asSelf ( ) { return < Self > < object > this ; } /**
     * TypeScript can't figure out that `this` is the `Self` so this private
     * method casts it in a few places where it's needed.
     */ protected asRoot ( ) { return < Root > < object > this ; } }