import { ObjectDictionary , isString } from "@opticss/util" ; import { LegacyRawSourceMap , adaptFromLegacySourceMap , parseSelector , postcss } from "opticss" ; import { RawSourceMap } from "source-map" ; import { Block } from "../BlockTree" ; import { Styles } from "../BlockTree/Styles" ; import { Options , ResolvedConfiguration , resolveConfiguration } from "../configuration" ; import { CssBlockError } from "../errors" ; import { ImportedCompiledCssFile , Importer } from "../importing" ; import { upgradeDefinitionFileSyntax } from "../PrecompiledDefinitions/block-syntax-version" ; import { ProcessedFile } from "./preprocessing" ; /**
 * This factory ensures that instances of a block are re-used when blocks are
 * going to be compiled/optimized together. Multiple instances of the same
 * block will result in analysis and optimization bugs.
 *
 * This also ensures that importers and preprocessors are correctly used when loading a block file.
 */ export class BlockFactoryBase { postcssImpl : typeof postcss ; importer : Importer ; configuration : ResolvedConfiguration ; blockNames : ObjectDictionary < string > ; faultTolerant : boolean ; private guids = new Set < string > ( ) ; constructor ( options , postcssImpl = postcss , faultTolerant = false ) { this . postcssImpl = postcssImpl ; this . configuration = resolveConfiguration ( options ) ; this . importer = this . configuration . importer ; this . blockNames = { } ; this . faultTolerant = faultTolerant ; } /**
     * Toss out any caches in this BlockFactory. Any future requests for a block
     * or block path will be loaded fresh from persistent storage.
     */ reset ( ) { this . blockNames = { } ; this . guids . clear ( ) ; } param block protected _surfaceBlockErrors ( block ) { if ( this . faultTolerant ) { return block ; } else { return block . assertValid ( ) ; } } protected _prepareDefinitionASTs ( file ) { file = upgradeDefinitionFileSyntax ( file ) ; const definitionAst = this . postcssImpl . parse ( file . definitionContents ) ; const dfnDebugIdentifier = this . importer . debugIdentifier ( file . definitionIdentifier , this . configuration ) ; const cssContentsAst = this . postcssImpl . parse ( file . cssContents ) ; const cssDebugIdentifier = this . importer . debugIdentifier ( file . identifier , this . configuration ) ; if ( ! definitionAst || ! definitionAst . nodes ) { throw new CssBlockError ( `Unable to parse definition file into AST!` , { filename : dfnDebugIdentifier , } ) ; } if ( ! cssContentsAst || ! cssContentsAst . nodes ) { throw new CssBlockError ( `Unable to parse CSS contents into AST!` , { filename : cssDebugIdentifier , } ) ; } return { definitionAst , cssContentsAst } ; } param block param cssContentsAst param file protected _mergeCssRulesIntoDefinitionBlock ( block , cssContentsAst , file ) { const styleNodesMap = block . presetClassesMap ( true ) ; cssContentsAst . walkRules ( rule => { const parsedSelectors = parseSelector ( rule ) ; parsedSelectors . forEach ( sel => { const keys = sel . key . nodes ; const keyStyleNodes = [ ] ; let doProcess = true ; keys . forEach ( key => { if ( key . type === "class" ) { const foundStyleNode = styleNodesMap [ key . value ] ; if ( ! foundStyleNode ) { doProcess = false ; return ; } keyStyleNodes . push ( foundStyleNode ) ; } } ) ; if ( doProcess ) { keyStyleNodes . forEach ( node => { node . rulesets . addRuleset ( this . configuration , file . identifier , rule ) ; } ) ; } } ) ; } ) ; } param name param doNotOverride return getUniqueBlockName ( name , identifier , doNotOverride = false ) { if ( ! this . blockNames [ name ] ) { this . blockNames [ name ] = identifier ; return name ; } if ( doNotOverride ) { return null ; } let i = 2 ; while ( this . blockNames [ `${ name }-${ i }` ] ) { i ++ ; } name = `${ name }-${ i }` ; this . blockNames [ name ] = identifier ; return name ; } param guid param identifier return registerGuid ( guid ) { if ( this . guids . has ( guid ) ) { return false ; } this . guids . add ( guid ) ; return true ; } } export function sourceMapFromProcessedFile ( result ) { let sourceMap = result . sourceMap ; if ( ! sourceMap && ! isString ( result . content ) && result . content . map ) { sourceMap = result . content . map . toJSON ( ) ; } if ( typeof sourceMap === "object" ) { return adaptFromLegacySourceMap ( sourceMap ) ; } else { return sourceMap ; } }