@@ -194,7 +194,8 @@ exports.main = function main(argv, options, callback) {
194
194
if ( ! stderr ) throw Error ( "'options.stderr' must be specified" ) ;
195
195
196
196
const opts = optionsUtil . parse ( argv , exports . options ) ;
197
- const args = opts . options ;
197
+ let args = opts . options ;
198
+
198
199
argv = opts . arguments ;
199
200
if ( args . noColors ) {
200
201
colorsUtil . stdout . supported =
@@ -270,6 +271,90 @@ exports.main = function main(argv, options, callback) {
270
271
271
272
// Set up base directory
272
273
const baseDir = args . baseDir ? path . resolve ( args . baseDir ) : "." ;
274
+ const target = args . target ;
275
+
276
+ // Once the baseDir is calculated, we can resolve the config, and its extensions
277
+ let asconfig = getAsconfig ( args . config , baseDir , readFile ) ;
278
+ let asconfigDir = baseDir ;
279
+
280
+ const seenAsconfig = new Set ( ) ;
281
+ seenAsconfig . add ( path . join ( baseDir , args . config ) ) ;
282
+
283
+ while ( asconfig ) {
284
+ // merge target first, then merge options, then merge extended asconfigs
285
+ if ( asconfig . targets && asconfig . targets [ target ] ) {
286
+ args = optionsUtil . merge ( exports . options , asconfig . targets [ target ] , args ) ;
287
+ }
288
+ if ( asconfig . options ) {
289
+ if ( asconfig . options . transform ) {
290
+ // ensure that a transform's path is relative to the current config
291
+ asconfig . options . transform = asconfig . options . transform . map ( p => {
292
+ if ( ! path . isAbsolute ( p ) ) {
293
+ if ( p . startsWith ( "." ) ) {
294
+ return path . join ( asconfigDir , p ) ;
295
+ }
296
+ return require . resolve ( p ) ;
297
+ }
298
+ return p ;
299
+ } ) ;
300
+ }
301
+ args = optionsUtil . merge ( exports . options , args , asconfig . options ) ;
302
+ }
303
+
304
+ // entries are added to the compilation
305
+ if ( asconfig . entries ) {
306
+ for ( const entry of asconfig . entries ) {
307
+ argv . push (
308
+ path . isAbsolute ( entry )
309
+ ? entry
310
+ // the entry is relative to the asconfig directory
311
+ : path . join ( asconfigDir , entry )
312
+ ) ;
313
+ }
314
+ }
315
+
316
+ // asconfig "extends" another config, merging options of it's parent
317
+ if ( asconfig . extends ) {
318
+ asconfigDir = path . isAbsolute ( asconfig . extends )
319
+ // absolute extension path means we know the exact directory and location
320
+ ? path . dirname ( asconfig . extends )
321
+ // relative means we need to calculate a relative asconfigDir
322
+ : path . join ( asconfigDir , path . dirname ( asconfig . extends ) ) ;
323
+ const fileName = path . basename ( asconfig . extends ) ;
324
+ const filePath = path . join ( asconfigDir , fileName ) ;
325
+ if ( seenAsconfig . has ( filePath ) ) {
326
+ asconfig = null ;
327
+ } else {
328
+ seenAsconfig . add ( filePath ) ;
329
+ asconfig = getAsconfig ( fileName , asconfigDir , readFile ) ;
330
+ }
331
+ } else {
332
+ asconfig = null ; // finished resolving the configuration chain
333
+ }
334
+ }
335
+
336
+ // If showConfig print args and exit
337
+ if ( args . showConfig ) {
338
+ stderr . write ( JSON . stringify ( args , null , 2 ) ) ;
339
+ return callback ( null ) ;
340
+ }
341
+
342
+ // This method resolves a path relative to the baseDir instead of process.cwd()
343
+ function resolveBasedir ( arg ) {
344
+ return path . resolve ( baseDir , arg ) ;
345
+ }
346
+
347
+ // create a unique set of values
348
+ function unique ( values ) {
349
+ return [ ...new Set ( values ) ] ;
350
+ }
351
+
352
+ // returns a relative path from baseDir
353
+ function makeRelative ( arg ) {
354
+ return path . relative ( baseDir , arg ) ;
355
+ }
356
+ // postprocess we need to get absolute file locations argv
357
+ argv = unique ( argv . map ( resolveBasedir ) ) . map ( makeRelative ) ;
273
358
274
359
// Set up options
275
360
const compilerOptions = assemblyscript . newOptions ( ) ;
@@ -347,7 +432,7 @@ exports.main = function main(argv, options, callback) {
347
432
const transforms = [ ] ;
348
433
if ( args . transform ) {
349
434
let tsNodeRegistered = false ;
350
- let transformArgs = args . transform ;
435
+ let transformArgs = unique ( args . transform . map ( resolveBasedir ) ) ;
351
436
for ( let i = 0 , k = transformArgs . length ; i < k ; ++ i ) {
352
437
let filename = transformArgs [ i ] . trim ( ) ;
353
438
if ( ! tsNodeRegistered && filename . endsWith ( ".ts" ) ) { // ts-node requires .ts specifically
@@ -376,6 +461,7 @@ exports.main = function main(argv, options, callback) {
376
461
}
377
462
}
378
463
}
464
+
379
465
function applyTransform ( name , ...args ) {
380
466
for ( let i = 0 , k = transforms . length ; i < k ; ++ i ) {
381
467
let transform = transforms [ i ] ;
@@ -400,11 +486,12 @@ exports.main = function main(argv, options, callback) {
400
486
assemblyscript . parse ( program , exports . libraryFiles [ libPath ] , exports . libraryPrefix + libPath + extension . ext , false ) ;
401
487
} ) ;
402
488
} ) ;
403
- const customLibDirs = [ ] ;
489
+ let customLibDirs = [ ] ;
404
490
if ( args . lib ) {
405
491
let lib = args . lib ;
406
- if ( typeof lib === "string" ) lib = lib . split ( "," ) ;
407
- Array . prototype . push . apply ( customLibDirs , lib . map ( lib => lib . trim ( ) ) ) ;
492
+ if ( typeof lib === "string" ) lib = lib . trim ( ) . split ( / \s * , \s * / ) ;
493
+ customLibDirs . push ( ...lib . map ( resolveBasedir ) ) ;
494
+ customLibDirs = unique ( customLibDirs ) ; // `lib` and `customLibDirs` may include duplicates
408
495
for ( let i = 0 , k = customLibDirs . length ; i < k ; ++ i ) { // custom
409
496
let libDir = customLibDirs [ i ] ;
410
497
let libFiles ;
@@ -574,7 +661,7 @@ exports.main = function main(argv, options, callback) {
574
661
const filename = argv [ i ] ;
575
662
576
663
let sourcePath = String ( filename ) . replace ( / \\ / g, "/" ) . replace ( extension . re , "" ) . replace ( / [ \\ / ] $ / , "" ) ;
577
-
664
+
578
665
// Setting the path to relative path
579
666
sourcePath = path . isAbsolute ( sourcePath ) ? path . relative ( baseDir , sourcePath ) : sourcePath ;
580
667
@@ -925,6 +1012,56 @@ exports.main = function main(argv, options, callback) {
925
1012
}
926
1013
} ;
927
1014
1015
+ const toString = Object . prototype . toString ;
1016
+
1017
+ function isObject ( arg ) {
1018
+ return toString . call ( arg ) === "[object Object]" ;
1019
+ }
1020
+
1021
+ function getAsconfig ( file , baseDir , readFile ) {
1022
+ const contents = readFile ( file , baseDir ) ;
1023
+ const location = path . join ( baseDir , file ) ;
1024
+ if ( ! contents ) return null ;
1025
+
1026
+ // obtain the configuration
1027
+ let config ;
1028
+ try {
1029
+ config = JSON . parse ( contents ) ;
1030
+ } catch ( ex ) {
1031
+ throw new Error ( "Asconfig is not valid json: " + location ) ;
1032
+ }
1033
+
1034
+ // validate asconfig shape
1035
+ if ( config . options && ! isObject ( config . options ) ) {
1036
+ throw new Error ( "Asconfig.options is not an object: " + location ) ;
1037
+ }
1038
+
1039
+ if ( config . include && ! Array . isArray ( config . include ) ) {
1040
+ throw new Error ( "Asconfig.include is not an array: " + location ) ;
1041
+ }
1042
+
1043
+ if ( config . targets ) {
1044
+ if ( ! isObject ( config . targets ) ) {
1045
+ throw new Error ( "Asconfig.targets is not an object: " + location ) ;
1046
+ }
1047
+ const targets = Object . keys ( config . targets ) ;
1048
+ for ( let i = 0 ; i < targets . length ; i ++ ) {
1049
+ const target = targets [ i ] ;
1050
+ if ( ! isObject ( config . targets [ target ] ) ) {
1051
+ throw new Error ( "Asconfig.targets." + target + " is not an object: " + location ) ;
1052
+ }
1053
+ }
1054
+ }
1055
+
1056
+ if ( config . extends && typeof config . extends !== "string" ) {
1057
+ throw new Error ( "Asconfig.extends is not a string: " + location ) ;
1058
+ }
1059
+
1060
+ return config ;
1061
+ }
1062
+
1063
+ exports . getAsconfig = getAsconfig ;
1064
+
928
1065
/** Checks diagnostics emitted so far for errors. */
929
1066
function checkDiagnostics ( program , stderr ) {
930
1067
var diagnostic ;
0 commit comments