import { posix as path } from 'path' ; import { SourceFile } from 'ts-simple-ast' ; import { AngularExternalTemplate , AngularExternalStyles , AngularExternalResource } from './external-resources/angular-external-resources.interfaces' ; import { AngularExternalTemplatesFileAnalyzer } from './external-templates/angular-external-templates.analyzer' ; import { AngularExternalTemplatesFileTransformer } from './external-templates/angular-external-templates.transformer' ; import { readFile } from '../utilities/read-file' ; import { AngularExternalStylesAnalyzer } from './external-styles/angular-external-styles.analyzer' ; import { AngularExternalStylesTransformer } from './external-styles/angular-external-styles.transformer' ; import { writeFile } from '../utilities/write-file' ; import { AngularPackage } from '../angular-package' ; import { AngularPackageLogger } from '../logger/angular-package-logger' ; /**
 * Angular Package Transformer
 */ export class AngularPackageTransformer { /**
     * Source files
     */ public get sourceFiles ( ) : Array < SourceFile > { return this . angularPackage . typescriptProject . getSourceFiles ( ) ; } ; /**
     * Angular Package
     */ private readonly angularPackage : AngularPackage ; param entryFilePath constructor ( angularPackage ) { this . angularPackage = angularPackage ; } returns public async transform ( ) { let numberOfFiles = this . sourceFiles . length ; let processedFiles = 0 ; await Promise . all ( this . sourceFiles . map ( async ( sourceFile ) : Promise < void > => { await this . inlineExternalTemplates ( sourceFile ) ; await this . inlineExternalStyles ( sourceFile ) ; this . convertLineBreaks ( sourceFile ) ; await this . save ( sourceFile ) ; processedFiles ++ ; const relativeFilePath = path . relative ( this . angularPackage . root , sourceFile . getFilePath ( ) ) ; const message = `Transform files (${ processedFiles }/${ numberOfFiles }) :: ${ relativeFilePath }` ; AngularPackageLogger . logMessage ( message ) ; } ) ) ; } param sourceFile returns private async inlineExternalTemplates ( sourceFile ) { await Promise . all ( AngularExternalTemplatesFileAnalyzer . getExternalTemplates ( sourceFile ) . map ( async ( externalTemplate ) : Promise < void > => { let template ; try { template = await readFile ( externalTemplate . template . path ) ; } catch ( error ) { this . handleExternalTemplateError ( 'An error occured while reading an external template.' , 'Make sure the template URL is correct, and the referenced template file does exist.' , externalTemplate , sourceFile , new Error ( `File System: ${ error . message . split ( '[' ) [ 1 ] . split ( ']' ) [ 0 ] }` ) ) ; } try { await AngularExternalTemplatesFileTransformer . inlineExternalTemplate ( externalTemplate , template ) ; } catch ( error ) { this . handleExternalTemplateError ( 'An error occured while transforming an external template.' , 'Make sure the external template has a supported file format and is syntactically correct.' , externalTemplate , sourceFile , error ) ; } } ) ) ; } param sourceFile returns private async inlineExternalStyles ( sourceFile ) { await Promise . all ( AngularExternalStylesAnalyzer . getExternalStyles ( sourceFile ) . map ( async ( externalStyle ) : Promise < void > => { const styles = await Promise . all ( externalStyle . styles . map ( async ( style ) : Promise < string > => { try { return await readFile ( style . path ) ; } catch ( error ) { this . handleExternalStyleError ( 'An error occured while reading an external style.' , 'Make sure the style URL is correct, and the referenced style file does exist.' , externalStyle , style , sourceFile , new Error ( `File System: ${ error . message . split ( '[' ) [ 1 ] . split ( ']' ) [ 0 ] }` ) ) ; } } ) ) ; await Promise . all ( styles . map ( async ( style , index ) : Promise < void > => { try { await AngularExternalStylesTransformer . inlineExternalStyle ( externalStyle , externalStyle . styles [ index ] , style ) ; } catch ( error ) { this . handleExternalStyleError ( 'An error occured while transforming an external style.' , 'Make sure the external style has a supported file format and is syntactically correct.' , externalStyle , externalStyle . styles [ index ] , sourceFile , error ) ; } } ) ) ; } ) ) ; } param sourceFile private convertLineBreaks ( sourceFile ) { sourceFile . formatText ( { newLineCharacter : '\n' } ) ; } param sourceFile returns private async save ( sourceFile ) { const absoluteEntryPath = path . join ( this . angularPackage . root , this . angularPackage . entryFile ) ; const absoluteOutputPath = path . join ( this . angularPackage . root , this . angularPackage . outDir ) ; const relativeFilePath = path . relative ( path . dirname ( absoluteEntryPath ) , sourceFile . getFilePath ( ) ) ; const filePathOut = path . join ( absoluteOutputPath , 'temp' , 'transformed' , relativeFilePath ) ; await writeFile ( filePathOut , sourceFile . getText ( ) ) ; } param message param tip param externalTemplate param sourceFile param details private handleExternalTemplateError ( message , tip , externalTemplate , sourceFile , details ) { const templateUrl = externalTemplate . template . node . getText ( ) . replace ( /'/g , '' ) ; const sourceFilePath = `./${ path . relative ( this . angularPackage . root , sourceFile . getFilePath ( ) ) }` ; const { line , character } = sourceFile . compilerNode . getLineAndCharacterOfPosition ( externalTemplate . node . getStart ( ) ) ; const templateFilePath = `./${ path . relative ( this . angularPackage . root , externalTemplate . template . path ) }` ; const origin = details . message . split ( ':' ) [ 0 ] ; const messageWithoutOrigin = details . message . split ( ':' ) . slice ( 1 ) . join ( ':' ) . trim ( ) ; const errorMessage = [ message , '' , `Message:        ${ messageWithoutOrigin }` , '' , `Caused by:      ${ origin }` , `File:           ${ sourceFilePath } (at ${ line + 1 }:${ character + 1 }) [to be transformed]` , `Template url:   ${ templateUrl }` , `Template file:  ${ templateFilePath }` , '' , `Tip: ${ tip }` ] . join ( '\n' ) ; AngularPackageLogger . logMessage ( errorMessage , 'error' ) ; throw new Error ( errorMessage ) ; } param message param tip param externalStyles param externalStyle param sourceFile param details private handleExternalStyleError ( message , tip , externalStyles , externalStyle , sourceFile , details ) { const styleUrl = externalStyle . node . getText ( ) . replace ( /'/g , '' ) ; const sourceFilePath = `./${ path . relative ( this . angularPackage . root , sourceFile . getFilePath ( ) ) }` ; const { line , character } = sourceFile . compilerNode . getLineAndCharacterOfPosition ( externalStyles . node . getStart ( ) ) ; const styleFilePath = `./${ path . relative ( this . angularPackage . root , externalStyle . path ) }` ; const origin = details . message . split ( ':' ) [ 0 ] ; const messageWithoutOrigin = details . message . split ( ':' ) . slice ( 1 ) . join ( ':' ) . trim ( ) ; const errorMessage = [ message , '' , `Message:     ${ messageWithoutOrigin }` , '' , `Caused by:   ${ origin }` , `File:        ${ sourceFilePath } (at ${ line + 1 }:${ character + 1 }) [to be transformed]` , `Style url:   ${ styleUrl }` , `Style file:  ${ styleFilePath }` , '' , `Tip: ${ tip }` ] . join ( '\n' ) ; AngularPackageLogger . logMessage ( errorMessage , 'error' ) ; throw new Error ( errorMessage ) ; } }