import { ObjectDictionary } from "@opticss/util" ; import { assert } from "chai" ; import * as path from "path" ; import { ImportedCompiledCssFile , ImportedFile , Importer , NodeJsImporter , ResolvedConfiguration , Syntax , } from "../../src" ; import { EMBEDDED_DEFINITION_TAG } from "../../src/importing/NodeJsImporter" ; const PROJECT_DIR = path . resolve ( __dirname , "../../.." ) ; export interface SourceWithSyntax { contents : string ; syntax : Syntax ; dfnContents ? : string ; dfnIdentifier ? : string ; hasEmbeddedDfnData ? : boolean ; } export type SourceRegistry = ObjectDictionary < SourceWithSyntax > ; export type ImportedFiles = ObjectDictionary < boolean > ; /**
 * A fake importer that behaves similar to the NodeJsImporter, but doesn't actually
 * read any files from the file system.
 */ export class MockImporter extends NodeJsImporter { registry : MockImportRegistry ; constructor ( registry ) { super ( ) ; this . registry = registry ; } identifier ( fromFile , importPath , _options ) { if ( fromFile ) { let sourceDir = path . dirname ( fromFile ) ; return this . registry . relativize ( path . resolve ( sourceDir , importPath ) ) ; } else { return importPath ; } } async import ( resolvedPath , configuration ) { return this . importSync ( resolvedPath , configuration ) ; } importSync ( resolvedPath , configuration ) { let source = this . registry . sources [ resolvedPath ] ; if ( ! source ) { let importedFiles = Object . keys ( this . registry . sources ) . join ( ", " ) ; throw new Error ( `Mock file ${ resolvedPath } not found. Available: ${ importedFiles }` ) ; } this . registry . imported [ resolvedPath ] = true ; if ( source . dfnContents && source . dfnIdentifier ) { const parsedSourceContents = this . segmentizeCompiledBlockCSS ( source . contents ) ; const blockCssContents = parsedSourceContents . blockCssContents ; const blockId = parsedSourceContents . blockId ; return { type : "ImportedCompiledCssFile" , syntax : Syntax . css , identifier : resolvedPath , cssContents : blockCssContents , definitionIdentifier : source . dfnIdentifier , definitionContents : source . dfnContents , blockId : blockId , defaultName : this . defaultName ( resolvedPath , configuration ) , rawCssContents : source . contents , } ; } else if ( source . hasEmbeddedDfnData ) { const parsedSourceContents = this . segmentizeCompiledBlockCSS ( source . contents ) ; const blockCssContents = parsedSourceContents . blockCssContents ; const blockId = parsedSourceContents . blockId ; const definitionIdentifier = `${ resolvedPath }${ EMBEDDED_DEFINITION_TAG }` ; const definitionContents = Buffer . from ( parsedSourceContents . definitionUrl . split ( "," ) [ 1 ] , "base64" ) . toString ( "utf-8" ) ; return { type : "ImportedCompiledCssFile" , syntax : Syntax . css , identifier : resolvedPath , cssContents : blockCssContents , definitionIdentifier , definitionContents , blockId : blockId , defaultName : this . defaultName ( resolvedPath , configuration ) , rawCssContents : source . contents , } ; } else { return { type : "ImportedFile" , syntax : source . syntax , identifier : resolvedPath , defaultName : this . defaultName ( resolvedPath , configuration ) , contents : source . contents , } ; } } } /**
 * A registry of sources that the MockImporter can pull files from. When writing
 * integration or acceptance tests, you can use this to avoid interacting with the
 * file system directly.
 */ export class MockImportRegistry { sources : SourceRegistry = { } ; imported : ImportedFiles = { } ; param sourcePath param contents param syntax param hasEmbeddedDfnData registerSource ( sourcePath , contents , syntax ? , hasEmbeddedDfnData ? ) { sourcePath = this . relativize ( sourcePath ) ; this . sources [ sourcePath ] = { contents : contents , syntax : syntax || Syntax . css , hasEmbeddedDfnData : hasEmbeddedDfnData || false , } ; } param sourcePath param cssContents param dfnIdentifier param dfnContents registerCompiledCssSource ( sourcePath , cssContents , dfnIdentifier , dfnContents ) { sourcePath = this . relativize ( sourcePath ) ; this . sources [ sourcePath ] = { contents : cssContents , syntax : Syntax . css , dfnContents , dfnIdentifier , } ; } param sourcePath markImported ( sourcePath ) { sourcePath = this . relativize ( sourcePath ) ; this . imported [ sourcePath ] = true ; } param sourcePath assertImported ( sourcePath ) { sourcePath = this . relativize ( sourcePath ) ; if ( ! this . imported [ sourcePath ] ) { let importedFiles = Object . keys ( this . imported ) . join ( ", " ) ; assert ( false , `${ sourcePath } was not imported as expected. These were imported: ${ importedFiles }` ) ; } } param absolutePath returns relativize ( absolutePath ) { if ( absolutePath . startsWith ( PROJECT_DIR ) ) { return absolutePath . slice ( PROJECT_DIR . length + 1 ) ; } else { return absolutePath ; } } returns importer ( ) { return new MockImporter ( this ) ; } /**
     * Resets the sources and imported paths in this registry, without fully destroying
     * the MockImporter or this instance.
     */ reset ( ) { this . sources = { } ; this . imported = { } ; } }