nl_tokens: appName may be null if config defines only 1 app
pl_tokens: function getConfig ( projectDir , appName , env ) { if ( ! [ 'dev' , 'test' , 'prod' ] . includes ( env ) ) exit ( ` ${ env } ` ) ; process . env . NODE_ENV = { dev : 'development' , test : 'testing' , prod : 'production' } [ env ] ; const configPath = path . join ( projectDir , 'basys.json' ) ; let projectConfig ; try { projectConfig = fs . readFileSync ( configPath , 'utf8' ) ; } catch ( e ) { exit ( ` ${ configPath } \n ` ) ; } try { projectConfig = JSON5 . parse ( projectConfig ) ; } catch ( e ) { exit ( ` ${ configPath } ${ e . message } \n ` + 'You can use JSON5 (https://json5.org) which is an extension of the JSON format, that includes:\n' + '  - comments,\n  - unquoted and single-quoted object keys,\n  - trailing commas,\n  - single-quoted and multi-line strings.\n' , ) ; } // BUG: Introduce some shortcuts for validating the configs, or use some library. App builder import function should do it. if ( ! projectConfig || projectConfig . constructor !== Object ) { exit ( ` ${ configPath } ` ) ; } if ( ! projectConfig . apps ) exit ( "'apps' option must be provided in basys.json" ) ; const appNames = Object . keys ( projectConfig . apps ) ; if ( appNames . length === 0 ) exit ( 'At least one app must be defined in basys.json' ) ; // BUG: validate that all appNames use allowed symbols only if ( ! appName ) { if ( appNames . length > 1 ) <mask> ( 'App name must be specified' ) ; appName = appNames [ 0 ] ; } if ( ! appNames . includes ( appName ) ) { exit ( ` ${ appName } ${ appNames . join ( "', '" ) } ` ) ; } let config = projectConfig . apps [ appName ] ; if ( ! [ 'web' , 'mobile' , 'desktop' ] . includes ( config . type ) ) { exit ( ` ${ appName } ${ config . type } ` , ) ; } // Default app configuration const defaultConfig = { entry : null , // Path to UI entry file (relative to src/ directory) favicon : null , styles : [ ] , overrides : { } , caseSensitive : false , sourceMap : false , host : 'localhost' , // In dev env another free port will be determined if this one is occupied. // In other envs the server will fail to start. port : 8080 , poll : false , // dev env only, see https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- custom : { } , // Holds custom config options (shouldn't overlap with any built-in options) } ; if ( config . type === 'web' ) { Object . assign ( defaultConfig , { backendEntry : null , // Path to backend entry file (relative to src/ directory) backendPort : 3000 , nodeVersion : env === 'dev' ? 'current' : '8.9' , browsers : [ '> 0.5%' , 'last 2 versions' , 'Firefox ESR' , 'not dead' ] , // BUG: automatically detect the browsers available on developer's machine? (only relevant if web app is present) // BUG: allow to override it via CLI arguments? // BUG: support remote browsers // Available values: 'chromium', 'chrome', 'chrome:headless', 'chrome-canary', 'ie', 'edge', // 'firefox', 'firefox:headless', 'opera', 'safari' testBrowsers : [ ] , } ) ; } // BUG: for mobile apps provide ios/android configuration, supported versions if ( config [ env ] ) { config = merge ( config , config [ env ] ) ; delete config . dev ; delete config . test ; delete config . prod ; } config = merge ( defaultConfig , config ) ; // Validate that custom options don't overlap with any built-in options for ( const key in config . custom ) { if ( key in config ) exit ( ` ${ key } ` ) ; } const tempDir = path . join ( projectDir , '.basys' , appName , env ) ; fs . ensureDirSync ( tempDir ) ; config = merge ( config , { appName , env , assetsPublicPath : '/' , // BUG: maybe set it to '/static/'? don't expose to user? tempDir , projectDir , distDir : env === 'prod' ? path . join ( projectDir , 'dist' , appName ) : tempDir , } ) ; // BUG: Validate both config files (depending on env), if invalid raise a meaningful error (with a link to local or public docs?) //      Look at https://github.com/mozilla/node-convict , https://github.com/ianstormtaylor/superstruct return config ; }