import path from 'path' ; import { existsSync } from 'fs' ; import fs from 'fs/promises' ; import { EntryObject } from 'webpack' ; import { logger , importUserModule } from '@reskript/core' ; import { AppEntry , EntryConfig } from '../interface' ; const ALLOWED_ENTRY_KEYS = new Set ( [ 'entry' , 'html' ] ) ; const validateEntryConfig = ( config , file ) => { const keys = Object . keys ( config ) ; if ( keys . some ( v => ! ALLOWED_ENTRY_KEYS . has ( v ) ) ) { logger . error ( `Entry configuration ${ file } has invalid keys, only "entry" and "html" are allowed.` ) ; process . exit ( 21 ) ; } } ; const readEntryConfig = async ( fileBaseName ) : Promise < EntryConfig > => { try { const { default : config } = await importUserModule < { default : EntryConfig ; } > ( fileBaseName , { default : { } } ) ; validateEntryConfig ( config , fileBaseName ) ; return config ; } catch ( ex ) { const message = ex instanceof Error ? ex . message : `${ ex }` ; logger . error ( `Unable to read entry configuration from ${ fileBaseName }: ${ message }` ) ; process . exit ( 22 ) ; } } ; const DEFAULT_HTML_TEMPLATE = path . resolve ( __dirname , '..' , 'assets' , 'default-html.ejs' ) ; const resolveEntryTemplate = ( file ) : string => { return existsSync ( file ) ? file : DEFAULT_HTML_TEMPLATE ; } ; const POSSIBLE_ENTRY_EXTENSION_REGEX = /\.[jt]sx?$/ ; const ALLOWED_ENTRY_EXTENSIONS = [ '.js' , '.jsx' , '.ts' , '.tsx' ] ; const resolveDirectoryEntry = async ( dir , shouldInclude ) => { const name = path . basename ( dir ) ; if ( ! shouldInclude ( name ) ) { return null ; } const possibleEntryFiles = ALLOWED_ENTRY_EXTENSIONS . map ( e => path . join ( dir , 'index' + e ) ) ; const entry = possibleEntryFiles . find ( existsSync ) ; if ( entry ) { const config = await readEntryConfig ( path . join ( dir , 'index.config' ) ) ; const appEntry = { name , config , file : entry , template : resolveEntryTemplate ( path . join ( dir , 'index.ejs' ) ) , } ; return appEntry ; } return null ; } ; const resolveFileEntry = async ( file , shouldInclude ) => { const extension = path . extname ( file ) ; if ( ! ALLOWED_ENTRY_EXTENSIONS . includes ( extension ) || file . includes ( '.config.' ) ) { return null ; } const name = path . basename ( file , extension ) ; if ( ! shouldInclude ( name ) ) { return null ; } const base = file . replace ( POSSIBLE_ENTRY_EXTENSION_REGEX , '' ) ; const config = await readEntryConfig ( `${ base }.config` ) ; const appEntry = { file , config , name : path . basename ( file , extension ) , template : resolveEntryTemplate ( `${ base }.ejs` ) , } ; return appEntry ; } ; export const resolveEntry = async ( targetBase , shouldInclude ) => { const stat = await fs . stat ( targetBase ) ; return stat . isDirectory ( ) ? resolveDirectoryEntry ( targetBase , shouldInclude ) : resolveFileEntry ( targetBase , shouldInclude ) ; } ; export const convertToWebpackEntry = ( { file , config } ) : EntryObject [ string ] => { if ( config . entry ) { return { import : file , ... config . entry , } ; } return file ; } ;