import { BaseImporter , Configuration , ImportedCompiledCssFile , ImportedFile , Importer , Syntax , syntaxFromExtension } from "@css-blocks/core" ; import * as debugGenerator from "debug" ; import type { FS as MergedFileSystem } from "fs-merger" ; import * as path from "path" ; const debug = debugGenerator ( "css-blocks:broccoli-tree-importer" ) ; const IDENTIFIER_PREFIX = "broccoli-tree:" ; const IDENTIFIER_PREFIX_LENGTH = IDENTIFIER_PREFIX . length ; const IDENTIFIER_PREFIX_RE = new RegExp ( `^${ IDENTIFIER_PREFIX }` ) ; export const EMBEDDED_DEFINITION_TAG = "#blockDefinitionURL" ; export function isBroccoliTreeIdentifier ( identifier ) { return ! ! ( identifier && IDENTIFIER_PREFIX_RE . test ( identifier ) ) ; } export function identToModulePath ( identifier ) { return identifier . replace ( IDENTIFIER_PREFIX , "" ) ; } export function identToPath ( input , identifier ) { if ( ! isBroccoliTreeIdentifier ( identifier ) ) { return identifier ; } let relativePath = identifier . substring ( IDENTIFIER_PREFIX_LENGTH ) ; if ( ! input . existsSync ( relativePath ) ) { debug ( `Couldn't find ${ relativePath }. Looking in addon-tree-output.` ) ; let addonRelativePath = `addon-tree-output/${ relativePath }` ; if ( input . existsSync ( addonRelativePath ) ) { relativePath = addonRelativePath ; } else { let addonModulesRelativePath = `addon-tree-output/modules/${ relativePath }` ; if ( input . existsSync ( addonModulesRelativePath ) ) { relativePath = addonModulesRelativePath ; } else { let lazyRelativePath = `lazy-tree-output/${ relativePath }` ; if ( input . existsSync ( lazyRelativePath ) ) { relativePath = lazyRelativePath ; } } } } return relativePath ; } export function pathToIdent ( relativePath ) { if ( isBroccoliTreeIdentifier ( relativePath ) ) { return relativePath ; } if ( relativePath . startsWith ( "lazy-tree-output/" ) ) { relativePath = relativePath . substring ( 17 ) ; } else if ( relativePath . startsWith ( "addon-tree-output/modules/" ) ) { relativePath = relativePath . substring ( 26 ) ; } else if ( relativePath . startsWith ( "addon-tree-output/" ) ) { relativePath = relativePath . substring ( 18 ) ; } if ( path . isAbsolute ( relativePath ) ) { return relativePath ; } else { return IDENTIFIER_PREFIX + relativePath ; } } /**
 * Knows how to import blocks from a broccoli merged filesystem interface.
 */ export class BroccoliTreeImporter extends BaseImporter { fallbackImporter : Importer ; input : MergedFileSystem ; namespace : string | null ; constructor ( input , namespace , fallbackImporter ) { super ( ) ; this . input = input ; this . fallbackImporter = fallbackImporter ; this . namespace = namespace ; } identifier ( fromIdentifier , importPath , config ) { if ( isBroccoliTreeIdentifier ( fromIdentifier ) ) { if ( importPath . startsWith ( "./" ) || importPath . startsWith ( "../" ) ) { let parsedPath = path . parse ( identToPath ( this . input , fromIdentifier ! ) ) ; let dir = "/" + parsedPath . dir ; let relativePath = path . resolve ( dir , importPath ) . substring ( 1 ) ; return pathToIdent ( relativePath ) ; } else { return this . fallbackImporter . identifier ( null , importPath , config ) ; } } else { return this . fallbackImporter . identifier ( fromIdentifier , importPath , config ) ; } } async import ( identifier , config ) { return this . importSync ( identifier , config ) ; } importSync ( identifier , config ) { if ( isBroccoliTreeIdentifier ( identifier ) ) { let relativePath = identToPath ( this . input , identifier ) ; let contents = this . input . readFileSync ( relativePath , "utf8" ) ; let syntax = syntaxFromExtension ( path . extname ( relativePath ) ) ; if ( this . isCompiledBlockCSS ( contents ) ) { const segmentedContents = this . segmentizeCompiledBlockCSS ( contents ) ; const dfnUrl = segmentedContents . definitionUrl ; let dfnData = null ; let definitionIdentifier = null ; if ( dfnUrl . startsWith ( "data:" ) ) { const [ dfnHeader , dfnEncodedData ] = dfnUrl . split ( "," ) ; definitionIdentifier = `${ identifier }${ EMBEDDED_DEFINITION_TAG }` ; if ( dfnHeader === "data:text/css;base64" ) { dfnData = Buffer . from ( dfnEncodedData , "base64" ) . toString ( "utf-8" ) ; } else { throw new Error ( `Definition data is in unsupported encoding or format. Embedded data must be in text/css;base64 format.\nFile Identifier: ${ identifier }\nFormat given: ${ dfnHeader }` ) ; } } else { throw new Error ( `Only embedded definition URLs are supported in ember at this time.` ) ; } dfnData = dfnData . trim ( ) ; definitionIdentifier = definitionIdentifier . trim ( ) ; debug ( "Importing definition file %s:\n%s" , definitionIdentifier , dfnData ) ; return { type : "ImportedCompiledCssFile" , syntax : Syntax . css , identifier , cssContents : segmentedContents . blockCssContents , blockId : segmentedContents . blockId , definitionContents : dfnData , definitionIdentifier , defaultName : this . defaultName ( identifier , config ) , rawCssContents : contents , } ; } else { return { type : "ImportedFile" , identifier , defaultName : this . defaultName ( identifier , config ) , syntax , contents , } ; } } else { return this . fallbackImporter . importSync ( identifier , config ) ; } } defaultName ( identifier , configuration ) { if ( isBroccoliTreeIdentifier ( identifier ) ) { let relativePath = identToPath ( this . input , identifier ) ; let defaultName = path . parse ( relativePath ) . name ; defaultName = defaultName . replace ( /.block$/ , "" ) ; if ( this . namespace ) { defaultName = `${ defaultName }-${ this . namespace }` ; } return defaultName ; } else { return this . fallbackImporter . defaultName ( identifier , configuration ) ; } } filesystemPath ( identifier , config ) { if ( isBroccoliTreeIdentifier ( identifier ) ) { let relativePath = identToPath ( this . input , identifier ) ; return relativePath ; } else { return this . fallbackImporter . filesystemPath ( identifier , config ) ; } } debugIdentifier ( identifier , config ) { if ( isBroccoliTreeIdentifier ( identifier ) ) { let relativePath = identToPath ( this . input , identifier ) ; return relativePath ; } else { return this . fallbackImporter . debugIdentifier ( identifier , config ) ; } } syntax ( identifier , config ) { if ( isBroccoliTreeIdentifier ( identifier ) ) { let relativePath = identToPath ( this . input , identifier ) ; let syntax = syntaxFromExtension ( path . extname ( relativePath ) ) ; return syntax ; } else { return this . fallbackImporter . syntax ( identifier , config ) ; } } }