github.com/evanw/esbuild@v0.21.4/internal/bundler_tests/bundler_tsconfig_test.go (about)

     1  package bundler_tests
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/evanw/esbuild/internal/config"
     7  )
     8  
     9  var tsconfig_suite = suite{
    10  	name: "tsconfig",
    11  }
    12  
    13  func TestTsconfigPaths(t *testing.T) {
    14  	tsconfig_suite.expectBundled(t, bundled{
    15  		files: map[string]string{
    16  			"/Users/user/project/entry.ts": `
    17  				import baseurl_dot from './baseurl_dot'
    18  				import baseurl_nested from './baseurl_nested'
    19  				console.log(baseurl_dot, baseurl_nested)
    20  			`,
    21  
    22  			// Tests with "baseUrl": "."
    23  			"/Users/user/project/baseurl_dot/index.ts": `
    24  				import test0 from 'test0'
    25  				import test1 from 'test1/foo'
    26  				import test2 from 'test2/foo'
    27  				import test3 from 'test3/foo'
    28  				import test4 from 'test4/foo'
    29  				import test5 from 'test5/foo'
    30  				import absoluteIn from './absolute-in'
    31  				import absoluteInStar from './absolute-in-star'
    32  				import absoluteOut from './absolute-out'
    33  				import absoluteOutStar from './absolute-out-star'
    34  				export default {
    35  					test0,
    36  					test1,
    37  					test2,
    38  					test3,
    39  					test4,
    40  					test5,
    41  					absoluteIn,
    42  					absoluteInStar,
    43  					absoluteOut,
    44  					absoluteOutStar,
    45  				}
    46  			`,
    47  			"/Users/user/project/baseurl_dot/tsconfig.json": `
    48  				{
    49  					"compilerOptions": {
    50  						"baseUrl": ".",
    51  						"paths": {
    52  							"test0": ["./test0-success.ts"],
    53  							"test1/*": ["./test1-success.ts"],
    54  							"test2/*": ["./test2-success/*"],
    55  							"t*t3/foo": ["./test3-succ*s.ts"],
    56  							"test4/*": ["./test4-first/*", "./test4-second/*"],
    57  							"test5/*": ["./test5-first/*", "./test5-second/*"],
    58  							"/virtual-in/test": ["./actual/test"],
    59  							"/virtual-in-star/*": ["./actual/*"],
    60  							"/virtual-out/test": ["/Users/user/project/baseurl_dot/actual/test"],
    61  							"/virtual-out-star/*": ["/Users/user/project/baseurl_dot/actual/*"],
    62  						}
    63  					}
    64  				}
    65  			`,
    66  			"/Users/user/project/baseurl_dot/test0-success.ts": `
    67  				export default 'test0-success'
    68  			`,
    69  			"/Users/user/project/baseurl_dot/test1-success.ts": `
    70  				export default 'test1-success'
    71  			`,
    72  			"/Users/user/project/baseurl_dot/test2-success/foo.ts": `
    73  				export default 'test2-success'
    74  			`,
    75  			"/Users/user/project/baseurl_dot/test3-success.ts": `
    76  				export default 'test3-success'
    77  			`,
    78  			"/Users/user/project/baseurl_dot/test4-first/foo.ts": `
    79  				export default 'test4-success'
    80  			`,
    81  			"/Users/user/project/baseurl_dot/test5-second/foo.ts": `
    82  				export default 'test5-success'
    83  			`,
    84  			"/Users/user/project/baseurl_dot/absolute-in.ts": `
    85  				export {default} from '/virtual-in/test'
    86  			`,
    87  			"/Users/user/project/baseurl_dot/absolute-in-star.ts": `
    88  				export {default} from '/virtual-in-star/test'
    89  			`,
    90  			"/Users/user/project/baseurl_dot/absolute-out.ts": `
    91  				export {default} from '/virtual-out/test'
    92  			`,
    93  			"/Users/user/project/baseurl_dot/absolute-out-star.ts": `
    94  				export {default} from '/virtual-out-star/test'
    95  			`,
    96  			"/Users/user/project/baseurl_dot/actual/test.ts": `
    97  				export default 'absolute-success'
    98  			`,
    99  
   100  			// Tests with "baseUrl": "nested"
   101  			"/Users/user/project/baseurl_nested/index.ts": `
   102  				import test0 from 'test0'
   103  				import test1 from 'test1/foo'
   104  				import test2 from 'test2/foo'
   105  				import test3 from 'test3/foo'
   106  				import test4 from 'test4/foo'
   107  				import test5 from 'test5/foo'
   108  				import absoluteIn from './absolute-in'
   109  				import absoluteInStar from './absolute-in-star'
   110  				import absoluteOut from './absolute-out'
   111  				import absoluteOutStar from './absolute-out-star'
   112  				export default {
   113  					test0,
   114  					test1,
   115  					test2,
   116  					test3,
   117  					test4,
   118  					test5,
   119  					absoluteIn,
   120  					absoluteInStar,
   121  					absoluteOut,
   122  					absoluteOutStar,
   123  				}
   124  			`,
   125  			"/Users/user/project/baseurl_nested/tsconfig.json": `
   126  				{
   127  					"compilerOptions": {
   128  						"baseUrl": "nested",
   129  						"paths": {
   130  							"test0": ["./test0-success.ts"],
   131  							"test1/*": ["./test1-success.ts"],
   132  							"test2/*": ["./test2-success/*"],
   133  							"t*t3/foo": ["./test3-succ*s.ts"],
   134  							"test4/*": ["./test4-first/*", "./test4-second/*"],
   135  							"test5/*": ["./test5-first/*", "./test5-second/*"],
   136  							"/virtual-in/test": ["./actual/test"],
   137  							"/virtual-in-star/*": ["./actual/*"],
   138  							"/virtual-out/test": ["/Users/user/project/baseurl_nested/nested/actual/test"],
   139  							"/virtual-out-star/*": ["/Users/user/project/baseurl_nested/nested/actual/*"],
   140  						}
   141  					}
   142  				}
   143  			`,
   144  			"/Users/user/project/baseurl_nested/nested/test0-success.ts": `
   145  				export default 'test0-success'
   146  			`,
   147  			"/Users/user/project/baseurl_nested/nested/test1-success.ts": `
   148  				export default 'test1-success'
   149  			`,
   150  			"/Users/user/project/baseurl_nested/nested/test2-success/foo.ts": `
   151  				export default 'test2-success'
   152  			`,
   153  			"/Users/user/project/baseurl_nested/nested/test3-success.ts": `
   154  				export default 'test3-success'
   155  			`,
   156  			"/Users/user/project/baseurl_nested/nested/test4-first/foo.ts": `
   157  				export default 'test4-success'
   158  			`,
   159  			"/Users/user/project/baseurl_nested/nested/test5-second/foo.ts": `
   160  				export default 'test5-success'
   161  			`,
   162  			"/Users/user/project/baseurl_nested/absolute-in.ts": `
   163  				export {default} from '/virtual-in/test'
   164  			`,
   165  			"/Users/user/project/baseurl_nested/absolute-in-star.ts": `
   166  				export {default} from '/virtual-in/test'
   167  			`,
   168  			"/Users/user/project/baseurl_nested/absolute-out.ts": `
   169  				export {default} from '/virtual-out/test'
   170  			`,
   171  			"/Users/user/project/baseurl_nested/absolute-out-star.ts": `
   172  				export {default} from '/virtual-out-star/test'
   173  			`,
   174  			"/Users/user/project/baseurl_nested/nested/actual/test.ts": `
   175  				export default 'absolute-success'
   176  			`,
   177  		},
   178  		entryPaths: []string{"/Users/user/project/entry.ts"},
   179  		options: config.Options{
   180  			Mode:          config.ModeBundle,
   181  			AbsOutputFile: "/Users/user/project/out.js",
   182  		},
   183  	})
   184  }
   185  
   186  func TestTsconfigPathsNoBaseURL(t *testing.T) {
   187  	tsconfig_suite.expectBundled(t, bundled{
   188  		files: map[string]string{
   189  			"/Users/user/project/entry.ts": `
   190  				import simple from './simple'
   191  				import extended from './extended'
   192  				console.log(simple, extended)
   193  			`,
   194  
   195  			// Tests with "baseUrl": "."
   196  			"/Users/user/project/simple/index.ts": `
   197  				import test0 from 'test0'
   198  				import test1 from 'test1/foo'
   199  				import test2 from 'test2/foo'
   200  				import test3 from 'test3/foo'
   201  				import test4 from 'test4/foo'
   202  				import test5 from 'test5/foo'
   203  				import absolute from './absolute'
   204  				export default {
   205  					test0,
   206  					test1,
   207  					test2,
   208  					test3,
   209  					test4,
   210  					test5,
   211  					absolute,
   212  				}
   213  			`,
   214  			"/Users/user/project/simple/tsconfig.json": `
   215  				{
   216  					"compilerOptions": {
   217  						"paths": {
   218  							"test0": ["./test0-success.ts"],
   219  							"test1/*": ["./test1-success.ts"],
   220  							"test2/*": ["./test2-success/*"],
   221  							"t*t3/foo": ["./test3-succ*s.ts"],
   222  							"test4/*": ["./test4-first/*", "./test4-second/*"],
   223  							"test5/*": ["./test5-first/*", "./test5-second/*"],
   224  							"/virtual/*": ["./actual/*"],
   225  						}
   226  					}
   227  				}
   228  			`,
   229  			"/Users/user/project/simple/test0-success.ts": `
   230  				export default 'test0-success'
   231  			`,
   232  			"/Users/user/project/simple/test1-success.ts": `
   233  				export default 'test1-success'
   234  			`,
   235  			"/Users/user/project/simple/test2-success/foo.ts": `
   236  				export default 'test2-success'
   237  			`,
   238  			"/Users/user/project/simple/test3-success.ts": `
   239  				export default 'test3-success'
   240  			`,
   241  			"/Users/user/project/simple/test4-first/foo.ts": `
   242  				export default 'test4-success'
   243  			`,
   244  			"/Users/user/project/simple/test5-second/foo.ts": `
   245  				export default 'test5-success'
   246  			`,
   247  			"/Users/user/project/simple/absolute.ts": `
   248  				export {default} from '/virtual/test'
   249  			`,
   250  			"/Users/user/project/simple/actual/test.ts": `
   251  				export default 'absolute-success'
   252  			`,
   253  
   254  			// Tests with "baseUrl": "nested"
   255  			"/Users/user/project/extended/index.ts": `
   256  				import test0 from 'test0'
   257  				import test1 from 'test1/foo'
   258  				import test2 from 'test2/foo'
   259  				import test3 from 'test3/foo'
   260  				import test4 from 'test4/foo'
   261  				import test5 from 'test5/foo'
   262  				import absolute from './absolute'
   263  				export default {
   264  					test0,
   265  					test1,
   266  					test2,
   267  					test3,
   268  					test4,
   269  					test5,
   270  					absolute,
   271  				}
   272  			`,
   273  			"/Users/user/project/extended/tsconfig.json": `
   274  				{
   275  					"extends": "./nested/tsconfig.json"
   276  				}
   277  			`,
   278  			"/Users/user/project/extended/nested/tsconfig.json": `
   279  				{
   280  					"compilerOptions": {
   281  						"paths": {
   282  							"test0": ["./test0-success.ts"],
   283  							"test1/*": ["./test1-success.ts"],
   284  							"test2/*": ["./test2-success/*"],
   285  							"t*t3/foo": ["./test3-succ*s.ts"],
   286  							"test4/*": ["./test4-first/*", "./test4-second/*"],
   287  							"test5/*": ["./test5-first/*", "./test5-second/*"],
   288  							"/virtual/*": ["./actual/*"],
   289  						}
   290  					}
   291  				}
   292  			`,
   293  			"/Users/user/project/extended/nested/test0-success.ts": `
   294  				export default 'test0-success'
   295  			`,
   296  			"/Users/user/project/extended/nested/test1-success.ts": `
   297  				export default 'test1-success'
   298  			`,
   299  			"/Users/user/project/extended/nested/test2-success/foo.ts": `
   300  				export default 'test2-success'
   301  			`,
   302  			"/Users/user/project/extended/nested/test3-success.ts": `
   303  				export default 'test3-success'
   304  			`,
   305  			"/Users/user/project/extended/nested/test4-first/foo.ts": `
   306  				export default 'test4-success'
   307  			`,
   308  			"/Users/user/project/extended/nested/test5-second/foo.ts": `
   309  				export default 'test5-success'
   310  			`,
   311  			"/Users/user/project/extended/absolute.ts": `
   312  				export {default} from '/virtual/test'
   313  			`,
   314  			"/Users/user/project/extended/nested/actual/test.ts": `
   315  				export default 'absolute-success'
   316  			`,
   317  		},
   318  		entryPaths: []string{"/Users/user/project/entry.ts"},
   319  		options: config.Options{
   320  			Mode:          config.ModeBundle,
   321  			AbsOutputFile: "/Users/user/project/out.js",
   322  		},
   323  	})
   324  }
   325  
   326  func TestTsconfigBadPathsNoBaseURL(t *testing.T) {
   327  	tsconfig_suite.expectBundled(t, bundled{
   328  		files: map[string]string{
   329  			"/Users/user/project/entry.ts": `
   330  				import "should-not-be-imported"
   331  			`,
   332  			"/Users/user/project/should-not-be-imported.ts": `
   333  			`,
   334  			"/Users/user/project/tsconfig.json": `
   335  				{
   336  					"compilerOptions": {
   337  						"paths": {
   338  							"test": [
   339  								".",
   340  								"..",
   341  								"./good",
   342  								".\\good",
   343  								"../good",
   344  								"..\\good",
   345  								"/good",
   346  								"\\good",
   347  								"c:/good",
   348  								"c:\\good",
   349  								"C:/good",
   350  								"C:\\good",
   351  
   352  								"bad",
   353  								"@bad/core",
   354  								".*/bad",
   355  								"..*/bad",
   356  								"c*:\\bad",
   357  								"c:*\\bad",
   358  								"http://bad"
   359  							]
   360  						}
   361  					}
   362  				}
   363  			`,
   364  		},
   365  		entryPaths: []string{"/Users/user/project/entry.ts"},
   366  		options: config.Options{
   367  			Mode:          config.ModeBundle,
   368  			AbsOutputFile: "/Users/user/project/out.js",
   369  		},
   370  		expectedScanLog: `Users/user/project/entry.ts: ERROR: Could not resolve "should-not-be-imported"
   371  NOTE: Use the relative path "./should-not-be-imported" to reference the file "Users/user/project/should-not-be-imported.ts". Without the leading "./", the path "should-not-be-imported" is being interpreted as a package path instead.
   372  Users/user/project/tsconfig.json: WARNING: Non-relative path "bad" is not allowed when "baseUrl" is not set (did you forget a leading "./"?)
   373  Users/user/project/tsconfig.json: WARNING: Non-relative path "@bad/core" is not allowed when "baseUrl" is not set (did you forget a leading "./"?)
   374  Users/user/project/tsconfig.json: WARNING: Non-relative path ".*/bad" is not allowed when "baseUrl" is not set (did you forget a leading "./"?)
   375  Users/user/project/tsconfig.json: WARNING: Non-relative path "..*/bad" is not allowed when "baseUrl" is not set (did you forget a leading "./"?)
   376  Users/user/project/tsconfig.json: WARNING: Non-relative path "c*:\\bad" is not allowed when "baseUrl" is not set (did you forget a leading "./"?)
   377  Users/user/project/tsconfig.json: WARNING: Non-relative path "c:*\\bad" is not allowed when "baseUrl" is not set (did you forget a leading "./"?)
   378  Users/user/project/tsconfig.json: WARNING: Non-relative path "http://bad" is not allowed when "baseUrl" is not set (did you forget a leading "./"?)
   379  `,
   380  	})
   381  }
   382  
   383  // https://github.com/evanw/esbuild/issues/913
   384  func TestTsconfigPathsOverriddenBaseURL(t *testing.T) {
   385  	tsconfig_suite.expectBundled(t, bundled{
   386  		files: map[string]string{
   387  			"/Users/user/project/src/entry.ts": `
   388  				import test from '#/test'
   389  				console.log(test)
   390  			`,
   391  			"/Users/user/project/src/test.ts": `
   392  				export default 123
   393  			`,
   394  			"/Users/user/project/tsconfig.json": `
   395  				{
   396  					"extends": "./tsconfig.paths.json",
   397  					"compilerOptions": {
   398  						"baseUrl": "./src"
   399  					}
   400  				}
   401  			`,
   402  			"/Users/user/project/tsconfig.paths.json": `
   403  				{
   404  					"compilerOptions": {
   405  						"paths": {
   406  							"#/*": ["./*"]
   407  						}
   408  					}
   409  				}
   410  			`,
   411  		},
   412  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
   413  		options: config.Options{
   414  			Mode:          config.ModeBundle,
   415  			AbsOutputFile: "/Users/user/project/out.js",
   416  		},
   417  	})
   418  }
   419  
   420  func TestTsconfigPathsOverriddenBaseURLDifferentDir(t *testing.T) {
   421  	tsconfig_suite.expectBundled(t, bundled{
   422  		files: map[string]string{
   423  			"/Users/user/project/src/entry.ts": `
   424  				import test from '#/test'
   425  				console.log(test)
   426  			`,
   427  			"/Users/user/project/src/test.ts": `
   428  				export default 123
   429  			`,
   430  			"/Users/user/project/src/tsconfig.json": `
   431  				{
   432  					"extends": "../tsconfig.paths.json",
   433  					"compilerOptions": {
   434  						"baseUrl": "./"
   435  					}
   436  				}
   437  			`,
   438  			"/Users/user/project/tsconfig.paths.json": `
   439  				{
   440  					"compilerOptions": {
   441  						"paths": {
   442  							"#/*": ["./*"]
   443  						}
   444  					}
   445  				}
   446  			`,
   447  		},
   448  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
   449  		options: config.Options{
   450  			Mode:          config.ModeBundle,
   451  			AbsOutputFile: "/Users/user/project/out.js",
   452  		},
   453  	})
   454  }
   455  
   456  func TestTsconfigPathsMissingBaseURL(t *testing.T) {
   457  	tsconfig_suite.expectBundled(t, bundled{
   458  		files: map[string]string{
   459  			"/Users/user/project/src/entry.ts": `
   460  				import test from '#/test'
   461  				console.log(test)
   462  			`,
   463  			"/Users/user/project/src/test.ts": `
   464  				export default 123
   465  			`,
   466  			"/Users/user/project/src/tsconfig.json": `
   467  				{
   468  					"extends": "../tsconfig.paths.json",
   469  					"compilerOptions": {
   470  					}
   471  				}
   472  			`,
   473  			"/Users/user/project/tsconfig.paths.json": `
   474  				{
   475  					"compilerOptions": {
   476  						"paths": {
   477  							"#/*": ["./*"]
   478  						}
   479  					}
   480  				}
   481  			`,
   482  		},
   483  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
   484  		options: config.Options{
   485  			Mode:          config.ModeBundle,
   486  			AbsOutputFile: "/Users/user/project/out.js",
   487  		},
   488  		expectedScanLog: `Users/user/project/src/entry.ts: ERROR: Could not resolve "#/test"
   489  NOTE: You can mark the path "#/test" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
   490  `,
   491  	})
   492  }
   493  
   494  func TestTsconfigPathsTypeOnly(t *testing.T) {
   495  	tsconfig_suite.expectBundled(t, bundled{
   496  		files: map[string]string{
   497  			"/Users/user/project/entry.ts": `
   498  				import { fib } from "fib";
   499  
   500  				console.log(fib(10));
   501  			`,
   502  			"/Users/user/project/node_modules/fib/index.js": `
   503  				export function fib(input) {
   504  					if (input < 2) {
   505  						return input;
   506  					}
   507  					return fib(input - 1) + fib(input - 2);
   508  				}
   509  			`,
   510  			"/Users/user/project/fib-local.d.ts": `
   511  				export function fib(input: number): number;
   512  			`,
   513  			"/Users/user/project/tsconfig.json": `
   514  				{
   515  					"compilerOptions": {
   516  						"baseUrl": ".",
   517  						"paths": {
   518  							"fib": ["fib-local.d.ts"]
   519  						}
   520  					}
   521  				}
   522  			`,
   523  		},
   524  		entryPaths: []string{"/Users/user/project/entry.ts"},
   525  		options: config.Options{
   526  			Mode:          config.ModeBundle,
   527  			AbsOutputFile: "/Users/user/project/out.js",
   528  		},
   529  	})
   530  }
   531  
   532  func TestTsconfigJSX(t *testing.T) {
   533  	tsconfig_suite.expectBundled(t, bundled{
   534  		files: map[string]string{
   535  			"/Users/user/project/entry.tsx": `
   536  				console.log(<><div/><div/></>)
   537  			`,
   538  			"/Users/user/project/tsconfig.json": `
   539  				{
   540  					"compilerOptions": {
   541  						"jsxFactory": "R.c",
   542  						"jsxFragmentFactory": "R.F"
   543  					}
   544  				}
   545  			`,
   546  		},
   547  		entryPaths: []string{"/Users/user/project/entry.tsx"},
   548  		options: config.Options{
   549  			Mode:          config.ModeBundle,
   550  			AbsOutputFile: "/Users/user/project/out.js",
   551  		},
   552  	})
   553  }
   554  
   555  func TestTsconfigNestedJSX(t *testing.T) {
   556  	tsconfig_suite.expectBundled(t, bundled{
   557  		files: map[string]string{
   558  			"/Users/user/project/entry.ts": `
   559  				import factory from './factory'
   560  				import fragment from './fragment'
   561  				import both from './both'
   562  				console.log(factory, fragment, both)
   563  			`,
   564  			"/Users/user/project/factory/index.tsx": `
   565  				export default <><div/><div/></>
   566  			`,
   567  			"/Users/user/project/factory/tsconfig.json": `
   568  				{
   569  					"compilerOptions": {
   570  						"jsxFactory": "h"
   571  					}
   572  				}
   573  			`,
   574  			"/Users/user/project/fragment/index.tsx": `
   575  				export default <><div/><div/></>
   576  			`,
   577  			"/Users/user/project/fragment/tsconfig.json": `
   578  				{
   579  					"compilerOptions": {
   580  						"jsxFragmentFactory": "a.b"
   581  					}
   582  				}
   583  			`,
   584  			"/Users/user/project/both/index.tsx": `
   585  				export default <><div/><div/></>
   586  			`,
   587  			"/Users/user/project/both/tsconfig.json": `
   588  				{
   589  					"compilerOptions": {
   590  						"jsxFactory": "R.c",
   591  						"jsxFragmentFactory": "R.F"
   592  					}
   593  				}
   594  			`,
   595  		},
   596  		entryPaths: []string{"/Users/user/project/entry.ts"},
   597  		options: config.Options{
   598  			Mode:          config.ModeBundle,
   599  			AbsOutputFile: "/Users/user/project/out.js",
   600  		},
   601  	})
   602  }
   603  
   604  func TestTsconfigPreserveJSX(t *testing.T) {
   605  	tsconfig_suite.expectBundled(t, bundled{
   606  		files: map[string]string{
   607  			"/Users/user/project/entry.tsx": `
   608  				console.log(<><div/><div/></>)
   609  			`,
   610  			"/Users/user/project/tsconfig.json": `
   611  				{
   612  					"compilerOptions": {
   613  						"jsx": "preserve" // This should be ignored
   614  					}
   615  				}
   616  			`,
   617  		},
   618  		entryPaths: []string{"/Users/user/project/entry.tsx"},
   619  		options: config.Options{
   620  			Mode:          config.ModeBundle,
   621  			AbsOutputFile: "/Users/user/project/out.js",
   622  		},
   623  	})
   624  }
   625  
   626  func TestTsconfigPreserveJSXAutomatic(t *testing.T) {
   627  	tsconfig_suite.expectBundled(t, bundled{
   628  		files: map[string]string{
   629  			"/Users/user/project/entry.tsx": `
   630  				console.log(<><div/><div/></>)
   631  			`,
   632  			"/Users/user/project/tsconfig.json": `
   633  				{
   634  					"compilerOptions": {
   635  						"jsx": "preserve" // This should be ignored
   636  					}
   637  				}
   638  			`,
   639  		},
   640  		entryPaths: []string{"/Users/user/project/entry.tsx"},
   641  		options: config.Options{
   642  			Mode:          config.ModeBundle,
   643  			AbsOutputFile: "/Users/user/project/out.js",
   644  			JSX: config.JSXOptions{
   645  				AutomaticRuntime: true,
   646  			},
   647  			ExternalSettings: config.ExternalSettings{
   648  				PreResolve: config.ExternalMatchers{Exact: map[string]bool{
   649  					"react/jsx-runtime": true,
   650  				}},
   651  			},
   652  		},
   653  	})
   654  }
   655  
   656  func TestTsconfigReactJSX(t *testing.T) {
   657  	tsconfig_suite.expectBundled(t, bundled{
   658  		files: map[string]string{
   659  			"/Users/user/project/entry.tsx": `
   660  				console.log(<><div/><div/></>)
   661  			`,
   662  			"/Users/user/project/tsconfig.json": `
   663  				{
   664  					"compilerOptions": {
   665  						"jsx": "react-jsx",
   666  						"jsxImportSource": "notreact"
   667  					}
   668  				}
   669  			`,
   670  		},
   671  		entryPaths: []string{"/Users/user/project/entry.tsx"},
   672  		options: config.Options{
   673  			Mode:          config.ModeBundle,
   674  			AbsOutputFile: "/Users/user/project/out.js",
   675  			ExternalSettings: config.ExternalSettings{
   676  				PreResolve: config.ExternalMatchers{Exact: map[string]bool{
   677  					"notreact/jsx-runtime": true,
   678  				}},
   679  			},
   680  		},
   681  	})
   682  }
   683  
   684  func TestTsconfigReactJSXDev(t *testing.T) {
   685  	tsconfig_suite.expectBundled(t, bundled{
   686  		files: map[string]string{
   687  			"/Users/user/project/entry.tsx": `
   688  				console.log(<><div/><div/></>)
   689  			`,
   690  			"/Users/user/project/tsconfig.json": `
   691  				{
   692  					"compilerOptions": {
   693  						"jsx": "react-jsxdev"
   694  					}
   695  				}
   696  			`,
   697  		},
   698  		entryPaths: []string{"/Users/user/project/entry.tsx"},
   699  		options: config.Options{
   700  			Mode:          config.ModeBundle,
   701  			AbsOutputFile: "/Users/user/project/out.js",
   702  			ExternalSettings: config.ExternalSettings{
   703  				PreResolve: config.ExternalMatchers{Exact: map[string]bool{
   704  					"react/jsx-dev-runtime": true,
   705  				}},
   706  			},
   707  		},
   708  	})
   709  }
   710  
   711  func TestTsconfigReactJSXWithDevInMainConfig(t *testing.T) {
   712  	tsconfig_suite.expectBundled(t, bundled{
   713  		files: map[string]string{
   714  			"/Users/user/project/entry.tsx": `
   715  				console.log(<><div/><div/></>)
   716  			`,
   717  			"/Users/user/project/tsconfig.json": `
   718  				{
   719  					"compilerOptions": {
   720  						"jsx": "react-jsx"
   721  					}
   722  				}
   723  			`,
   724  		},
   725  		entryPaths: []string{"/Users/user/project/entry.tsx"},
   726  		options: config.Options{
   727  			Mode:          config.ModeBundle,
   728  			AbsOutputFile: "/Users/user/project/out.js",
   729  			JSX: config.JSXOptions{
   730  				Development: true,
   731  			},
   732  			ExternalSettings: config.ExternalSettings{
   733  				PreResolve: config.ExternalMatchers{Exact: map[string]bool{
   734  					"react/jsx-dev-runtime": true,
   735  				}},
   736  			},
   737  		},
   738  	})
   739  }
   740  
   741  func TestTsconfigJsonBaseUrl(t *testing.T) {
   742  	tsconfig_suite.expectBundled(t, bundled{
   743  		files: map[string]string{
   744  			"/Users/user/project/src/app/entry.js": `
   745  				import fn from 'lib/util'
   746  				console.log(fn())
   747  			`,
   748  			"/Users/user/project/src/tsconfig.json": `
   749  				{
   750  					"compilerOptions": {
   751  						"baseUrl": "."
   752  					}
   753  				}
   754  			`,
   755  			"/Users/user/project/src/lib/util.js": `
   756  				module.exports = function() {
   757  					return 123
   758  				}
   759  			`,
   760  		},
   761  		entryPaths: []string{"/Users/user/project/src/app/entry.js"},
   762  		options: config.Options{
   763  			Mode:          config.ModeBundle,
   764  			AbsOutputFile: "/Users/user/project/out.js",
   765  		},
   766  	})
   767  }
   768  
   769  func TestJsconfigJsonBaseUrl(t *testing.T) {
   770  	tsconfig_suite.expectBundled(t, bundled{
   771  		files: map[string]string{
   772  			"/Users/user/project/src/app/entry.js": `
   773  				import fn from 'lib/util'
   774  				console.log(fn())
   775  			`,
   776  			"/Users/user/project/src/jsconfig.json": `
   777  				{
   778  					"compilerOptions": {
   779  						"baseUrl": "."
   780  					}
   781  				}
   782  			`,
   783  			"/Users/user/project/src/lib/util.js": `
   784  				module.exports = function() {
   785  					return 123
   786  				}
   787  			`,
   788  		},
   789  		entryPaths: []string{"/Users/user/project/src/app/entry.js"},
   790  		options: config.Options{
   791  			Mode:          config.ModeBundle,
   792  			AbsOutputFile: "/Users/user/project/out.js",
   793  		},
   794  	})
   795  }
   796  
   797  func TestTsconfigJsonAbsoluteBaseUrl(t *testing.T) {
   798  	tsconfig_suite.expectBundled(t, bundled{
   799  		files: map[string]string{
   800  			"/Users/user/project/src/app/entry.js": `
   801  				import fn from 'lib/util'
   802  				console.log(fn())
   803  			`,
   804  			"/Users/user/project/src/tsconfig.json": `
   805  				{
   806  					"compilerOptions": {
   807  						"baseUrl": "/Users/user/project/src"
   808  					}
   809  				}
   810  			`,
   811  			"/Users/user/project/src/lib/util.js": `
   812  				module.exports = function() {
   813  					return 123
   814  				}
   815  			`,
   816  		},
   817  		entryPaths: []string{"/Users/user/project/src/app/entry.js"},
   818  		options: config.Options{
   819  			Mode:          config.ModeBundle,
   820  			AbsOutputFile: "/Users/user/project/out.js",
   821  		},
   822  	})
   823  }
   824  
   825  func TestTsconfigJsonCommentAllowed(t *testing.T) {
   826  	tsconfig_suite.expectBundled(t, bundled{
   827  		files: map[string]string{
   828  			"/Users/user/project/src/app/entry.js": `
   829  				import fn from 'lib/util'
   830  				console.log(fn())
   831  			`,
   832  			"/Users/user/project/src/tsconfig.json": `
   833  				{
   834  					// Single-line comment
   835  					"compilerOptions": {
   836  						"baseUrl": "."
   837  					}
   838  				}
   839  			`,
   840  			"/Users/user/project/src/lib/util.js": `
   841  				module.exports = function() {
   842  					return 123
   843  				}
   844  			`,
   845  		},
   846  		entryPaths: []string{"/Users/user/project/src/app/entry.js"},
   847  		options: config.Options{
   848  			Mode:          config.ModeBundle,
   849  			AbsOutputFile: "/Users/user/project/out.js",
   850  		},
   851  	})
   852  }
   853  
   854  func TestTsconfigJsonTrailingCommaAllowed(t *testing.T) {
   855  	tsconfig_suite.expectBundled(t, bundled{
   856  		files: map[string]string{
   857  			"/Users/user/project/src/app/entry.js": `
   858  				import fn from 'lib/util'
   859  				console.log(fn())
   860  			`,
   861  			"/Users/user/project/src/tsconfig.json": `
   862  				{
   863  					"compilerOptions": {
   864  						"baseUrl": ".",
   865  					},
   866  				}
   867  			`,
   868  			"/Users/user/project/src/lib/util.js": `
   869  				module.exports = function() {
   870  					return 123
   871  				}
   872  			`,
   873  		},
   874  		entryPaths: []string{"/Users/user/project/src/app/entry.js"},
   875  		options: config.Options{
   876  			Mode:          config.ModeBundle,
   877  			AbsOutputFile: "/Users/user/project/out.js",
   878  		},
   879  	})
   880  }
   881  
   882  func TestTsconfigJsonExtends(t *testing.T) {
   883  	tsconfig_suite.expectBundled(t, bundled{
   884  		files: map[string]string{
   885  			"/entry.jsx": `
   886  				console.log(<div/>, <></>)
   887  			`,
   888  			"/tsconfig.json": `
   889  				{
   890  					"extends": "./base",
   891  					"compilerOptions": {
   892  						"jsxFragmentFactory": "derivedFragment"
   893  					}
   894  				}
   895  			`,
   896  			"/base.json": `
   897  				{
   898  					"compilerOptions": {
   899  						"jsxFactory": "baseFactory",
   900  						"jsxFragmentFactory": "baseFragment"
   901  					}
   902  				}
   903  			`,
   904  		},
   905  		entryPaths: []string{"/entry.jsx"},
   906  		options: config.Options{
   907  			Mode:          config.ModeBundle,
   908  			AbsOutputFile: "/out.js",
   909  		},
   910  	})
   911  }
   912  
   913  func TestTsconfigJsonExtendsAbsolute(t *testing.T) {
   914  	tsconfig_suite.expectBundledUnix(t, bundled{
   915  		files: map[string]string{
   916  			"/Users/user/project/entry.jsx": `
   917  				console.log(<div/>, <></>)
   918  			`,
   919  			"/Users/user/project/tsconfig.json": `
   920  				{
   921  					"extends": "/Users/user/project/base.json",
   922  					"compilerOptions": {
   923  						"jsxFragmentFactory": "derivedFragment"
   924  					}
   925  				}
   926  			`,
   927  			"/Users/user/project/base.json": `
   928  				{
   929  					"compilerOptions": {
   930  						"jsxFactory": "baseFactory",
   931  						"jsxFragmentFactory": "baseFragment"
   932  					}
   933  				}
   934  			`,
   935  		},
   936  		entryPaths: []string{"/Users/user/project/entry.jsx"},
   937  		options: config.Options{
   938  			Mode:          config.ModeBundle,
   939  			AbsOutputFile: "/out.js",
   940  		},
   941  	})
   942  
   943  	tsconfig_suite.expectBundledWindows(t, bundled{
   944  		files: map[string]string{
   945  			"/Users/user/project/entry.jsx": `
   946  				console.log(<div/>, <></>)
   947  			`,
   948  			"/Users/user/project/tsconfig.json": `
   949  				{
   950  					"extends": "C:\\Users\\user\\project\\base.json",
   951  					"compilerOptions": {
   952  						"jsxFragmentFactory": "derivedFragment"
   953  					}
   954  				}
   955  			`,
   956  			"/Users/user/project/base.json": `
   957  				{
   958  					"compilerOptions": {
   959  						"jsxFactory": "baseFactory",
   960  						"jsxFragmentFactory": "baseFragment"
   961  					}
   962  				}
   963  			`,
   964  		},
   965  		entryPaths: []string{"/Users/user/project/entry.jsx"},
   966  		options: config.Options{
   967  			Mode:          config.ModeBundle,
   968  			AbsOutputFile: "/out.js",
   969  		},
   970  	})
   971  }
   972  
   973  func TestTsconfigJsonExtendsThreeLevels(t *testing.T) {
   974  	tsconfig_suite.expectBundled(t, bundled{
   975  		files: map[string]string{
   976  			"/Users/user/project/src/entry.jsx": `
   977  				import "test/import.js"
   978  				console.log(<div/>, <></>)
   979  			`,
   980  			"/Users/user/project/src/tsconfig.json": `
   981  				{
   982  					"extends": "./path1/base",
   983  					"compilerOptions": {
   984  						"jsxFragmentFactory": "derivedFragment"
   985  					}
   986  				}
   987  			`,
   988  			"/Users/user/project/src/path1/base.json": `
   989  				{
   990  					"extends": "../path2/base2"
   991  				}
   992  			`,
   993  			"/Users/user/project/src/path2/base2.json": `
   994  				{
   995  					"compilerOptions": {
   996  						"baseUrl": ".",
   997  						"paths": {
   998  							"test/*": ["./works/*"]
   999  						},
  1000  						"jsxFactory": "baseFactory",
  1001  						"jsxFragmentFactory": "baseFragment"
  1002  					}
  1003  				}
  1004  			`,
  1005  			"/Users/user/project/src/path2/works/import.js": `
  1006  				console.log('works')
  1007  			`,
  1008  		},
  1009  		entryPaths: []string{"/Users/user/project/src/entry.jsx"},
  1010  		options: config.Options{
  1011  			Mode:          config.ModeBundle,
  1012  			AbsOutputFile: "/out.js",
  1013  		},
  1014  	})
  1015  }
  1016  
  1017  func TestTsconfigJsonExtendsLoop(t *testing.T) {
  1018  	tsconfig_suite.expectBundled(t, bundled{
  1019  		files: map[string]string{
  1020  			"/entry.js": `
  1021  				console.log(123)
  1022  			`,
  1023  			"/tsconfig.json": `
  1024  				{
  1025  					"extends": "./base.json"
  1026  				}
  1027  			`,
  1028  			"/base.json": `
  1029  				{
  1030  					"extends": "./tsconfig"
  1031  				}
  1032  			`,
  1033  		},
  1034  		entryPaths: []string{"/entry.js"},
  1035  		options: config.Options{
  1036  			Mode:          config.ModeBundle,
  1037  			AbsOutputFile: "/out.js",
  1038  		},
  1039  		expectedScanLog: `base.json: WARNING: Base config file "./tsconfig" forms cycle
  1040  `,
  1041  	})
  1042  }
  1043  
  1044  func TestTsconfigJsonExtendsPackage(t *testing.T) {
  1045  	tsconfig_suite.expectBundled(t, bundled{
  1046  		files: map[string]string{
  1047  			"/Users/user/project/src/app/entry.jsx": `
  1048  				console.log(<div/>)
  1049  			`,
  1050  			"/Users/user/project/src/tsconfig.json": `
  1051  				{
  1052  					"extends": "@package/foo/tsconfig.json"
  1053  				}
  1054  			`,
  1055  			"/Users/user/project/node_modules/@package/foo/tsconfig.json": `
  1056  				{
  1057  					"compilerOptions": {
  1058  						"jsxFactory": "worked"
  1059  					}
  1060  				}
  1061  			`,
  1062  		},
  1063  		entryPaths: []string{"/Users/user/project/src/app/entry.jsx"},
  1064  		options: config.Options{
  1065  			Mode:          config.ModeBundle,
  1066  			AbsOutputFile: "/Users/user/project/out.js",
  1067  		},
  1068  	})
  1069  }
  1070  
  1071  func TestTsconfigJsonOverrideMissing(t *testing.T) {
  1072  	tsconfig_suite.expectBundled(t, bundled{
  1073  		files: map[string]string{
  1074  			"/Users/user/project/src/app/entry.ts": `
  1075  				import 'foo'
  1076  			`,
  1077  			"/Users/user/project/src/foo-bad.ts": `
  1078  				console.log('bad')
  1079  			`,
  1080  			"/Users/user/project/src/tsconfig.json": `
  1081  				{
  1082  					"compilerOptions": {
  1083  						"baseUrl": ".",
  1084  						"paths": {
  1085  							"foo": ["./foo-bad.ts"]
  1086  						}
  1087  					}
  1088  				}
  1089  			`,
  1090  			"/Users/user/project/other/foo-good.ts": `
  1091  				console.log('good')
  1092  			`,
  1093  			"/Users/user/project/other/config-for-ts.json": `
  1094  				{
  1095  					"compilerOptions": {
  1096  						"baseUrl": ".",
  1097  						"paths": {
  1098  							"foo": ["./foo-good.ts"]
  1099  						}
  1100  					}
  1101  				}
  1102  			`,
  1103  		},
  1104  		entryPaths: []string{"/Users/user/project/src/app/entry.ts"},
  1105  		options: config.Options{
  1106  			Mode:          config.ModeBundle,
  1107  			AbsOutputFile: "/Users/user/project/out.js",
  1108  			TSConfigPath:  "/Users/user/project/other/config-for-ts.json",
  1109  		},
  1110  	})
  1111  }
  1112  
  1113  func TestTsconfigJsonOverrideNodeModules(t *testing.T) {
  1114  	tsconfig_suite.expectBundled(t, bundled{
  1115  		files: map[string]string{
  1116  			"/Users/user/project/src/app/entry.ts": `
  1117  				import 'foo'
  1118  			`,
  1119  			"/Users/user/project/src/node_modules/foo/index.js": `
  1120  				console.log('default')
  1121  			`,
  1122  			"/Users/user/project/src/foo-bad.ts": `
  1123  				console.log('bad')
  1124  			`,
  1125  			"/Users/user/project/src/tsconfig.json": `
  1126  				{
  1127  					"compilerOptions": {
  1128  						"baseUrl": ".",
  1129  						"paths": {
  1130  							"foo": ["./foo-bad.ts"]
  1131  						}
  1132  					}
  1133  				}
  1134  			`,
  1135  			"/Users/user/project/other/foo-good.ts": `
  1136  				console.log('good')
  1137  			`,
  1138  			"/Users/user/project/other/config-for-ts.json": `
  1139  				{
  1140  					"compilerOptions": {
  1141  						"baseUrl": ".",
  1142  						"paths": {
  1143  							"foo": ["./foo-good.ts"]
  1144  						}
  1145  					}
  1146  				}
  1147  			`,
  1148  		},
  1149  		entryPaths: []string{"/Users/user/project/src/app/entry.ts"},
  1150  		options: config.Options{
  1151  			Mode:          config.ModeBundle,
  1152  			AbsOutputFile: "/Users/user/project/out.js",
  1153  			TSConfigPath:  "/Users/user/project/other/config-for-ts.json",
  1154  		},
  1155  	})
  1156  }
  1157  
  1158  func TestTsconfigJsonOverrideInvalid(t *testing.T) {
  1159  	tsconfig_suite.expectBundled(t, bundled{
  1160  		files: map[string]string{
  1161  			"/entry.ts": ``,
  1162  		},
  1163  		entryPaths: []string{"/entry.ts"},
  1164  		options: config.Options{
  1165  			Mode:          config.ModeBundle,
  1166  			AbsOutputFile: "/out.js",
  1167  			TSConfigPath:  "/this/file/doesn't/exist/tsconfig.json",
  1168  		},
  1169  		expectedScanLog: `ERROR: Cannot find tsconfig file "this/file/doesn't/exist/tsconfig.json"
  1170  `,
  1171  	})
  1172  }
  1173  
  1174  func TestTsconfigJsonNodeModulesImplicitFile(t *testing.T) {
  1175  	tsconfig_suite.expectBundled(t, bundled{
  1176  		files: map[string]string{
  1177  			"/Users/user/project/src/app/entry.tsx": `
  1178  				console.log(<div/>)
  1179  			`,
  1180  			"/Users/user/project/src/tsconfig.json": `
  1181  				{
  1182  					"extends": "foo"
  1183  				}
  1184  			`,
  1185  			"/Users/user/project/src/node_modules/foo/tsconfig.json": `
  1186  				{
  1187  					"compilerOptions": {
  1188  						"jsx": "react",
  1189  						"jsxFactory": "worked"
  1190  					}
  1191  				}
  1192  			`,
  1193  		},
  1194  		entryPaths: []string{"/Users/user/project/src/app/entry.tsx"},
  1195  		options: config.Options{
  1196  			Mode:          config.ModeBundle,
  1197  			AbsOutputFile: "/Users/user/project/out.js",
  1198  		},
  1199  	})
  1200  }
  1201  
  1202  func TestTsconfigJsonNodeModulesTsconfigPathExact(t *testing.T) {
  1203  	tsconfig_suite.expectBundled(t, bundled{
  1204  		files: map[string]string{
  1205  			"/Users/user/project/src/app/entry.tsx": `
  1206  				console.log(<div/>)
  1207  			`,
  1208  			"/Users/user/project/src/tsconfig.json": `
  1209  				{
  1210  					"extends": "foo"
  1211  				}
  1212  			`,
  1213  			"/Users/user/project/src/node_modules/foo/package.json": `
  1214  				{
  1215  					"tsconfig": "over/here.json"
  1216  				}
  1217  			`,
  1218  			"/Users/user/project/src/node_modules/foo/over/here.json": `
  1219  				{
  1220  					"compilerOptions": {
  1221  						"jsx": "react",
  1222  						"jsxFactory": "worked"
  1223  					}
  1224  				}
  1225  			`,
  1226  		},
  1227  		entryPaths: []string{"/Users/user/project/src/app/entry.tsx"},
  1228  		options: config.Options{
  1229  			Mode:          config.ModeBundle,
  1230  			AbsOutputFile: "/Users/user/project/out.js",
  1231  		},
  1232  	})
  1233  }
  1234  
  1235  func TestTsconfigJsonNodeModulesTsconfigPathImplicitJson(t *testing.T) {
  1236  	tsconfig_suite.expectBundled(t, bundled{
  1237  		files: map[string]string{
  1238  			"/Users/user/project/src/app/entry.tsx": `
  1239  				console.log(<div/>)
  1240  			`,
  1241  			"/Users/user/project/src/tsconfig.json": `
  1242  				{
  1243  					"extends": "foo"
  1244  				}
  1245  			`,
  1246  			"/Users/user/project/src/node_modules/foo/package.json": `
  1247  				{
  1248  					"tsconfig": "over/here"
  1249  				}
  1250  			`,
  1251  			"/Users/user/project/src/node_modules/foo/over/here.json": `
  1252  				{
  1253  					"compilerOptions": {
  1254  						"jsx": "react",
  1255  						"jsxFactory": "worked"
  1256  					}
  1257  				}
  1258  			`,
  1259  		},
  1260  		entryPaths: []string{"/Users/user/project/src/app/entry.tsx"},
  1261  		options: config.Options{
  1262  			Mode:          config.ModeBundle,
  1263  			AbsOutputFile: "/Users/user/project/out.js",
  1264  		},
  1265  	})
  1266  }
  1267  
  1268  func TestTsconfigJsonNodeModulesTsconfigPathDirectory(t *testing.T) {
  1269  	tsconfig_suite.expectBundled(t, bundled{
  1270  		files: map[string]string{
  1271  			"/Users/user/project/src/app/entry.tsx": `
  1272  				console.log(<div/>)
  1273  			`,
  1274  			"/Users/user/project/src/tsconfig.json": `
  1275  				{
  1276  					"extends": "foo"
  1277  				}
  1278  			`,
  1279  			"/Users/user/project/src/node_modules/foo/package.json": `
  1280  				{
  1281  					"tsconfig": "over/here"
  1282  				}
  1283  			`,
  1284  			"/Users/user/project/src/node_modules/foo/over/here/tsconfig.json": `
  1285  				{
  1286  					"compilerOptions": {
  1287  						"jsx": "react",
  1288  						"jsxFactory": "worked"
  1289  					}
  1290  				}
  1291  			`,
  1292  		},
  1293  		entryPaths: []string{"/Users/user/project/src/app/entry.tsx"},
  1294  		options: config.Options{
  1295  			Mode:          config.ModeBundle,
  1296  			AbsOutputFile: "/Users/user/project/out.js",
  1297  		},
  1298  	})
  1299  }
  1300  
  1301  func TestTsconfigJsonNodeModulesTsconfigPathBad(t *testing.T) {
  1302  	tsconfig_suite.expectBundled(t, bundled{
  1303  		files: map[string]string{
  1304  			"/Users/user/project/src/app/entry.tsx": `
  1305  				console.log(<div/>)
  1306  			`,
  1307  			"/Users/user/project/src/tsconfig.json": `
  1308  				{
  1309  					"extends": "foo"
  1310  				}
  1311  			`,
  1312  			"/Users/user/project/src/node_modules/foo/package.json": `
  1313  				{
  1314  					"tsconfig": "over/here.json"
  1315  				}
  1316  			`,
  1317  			"/Users/user/project/src/node_modules/foo/tsconfig.json": `
  1318  				{
  1319  					"compilerOptions": {
  1320  						"jsx": "react",
  1321  						"jsxFactory": "THIS SHOULD NOT BE LOADED"
  1322  					}
  1323  				}
  1324  			`,
  1325  		},
  1326  		entryPaths: []string{"/Users/user/project/src/app/entry.tsx"},
  1327  		options: config.Options{
  1328  			Mode:          config.ModeBundle,
  1329  			AbsOutputFile: "/Users/user/project/out.js",
  1330  		},
  1331  		expectedScanLog: `Users/user/project/src/tsconfig.json: WARNING: Cannot find base config file "foo"
  1332  `,
  1333  	})
  1334  }
  1335  
  1336  func TestTsconfigJsonInsideNodeModules(t *testing.T) {
  1337  	tsconfig_suite.expectBundled(t, bundled{
  1338  		files: map[string]string{
  1339  			"/Users/user/project/src/app/entry.tsx": `
  1340  				import 'foo'
  1341  			`,
  1342  			"/Users/user/project/src/node_modules/foo/index.tsx": `
  1343  				console.log(<div/>)
  1344  			`,
  1345  			"/Users/user/project/src/node_modules/foo/tsconfig.json": `
  1346  				{
  1347  					"compilerOptions": {
  1348  						"jsxFactory": "TEST_FAILED"
  1349  					}
  1350  				}
  1351  			`,
  1352  		},
  1353  		entryPaths: []string{"/Users/user/project/src/app/entry.tsx"},
  1354  		options: config.Options{
  1355  			Mode:          config.ModeBundle,
  1356  			AbsOutputFile: "/Users/user/project/out.js",
  1357  		},
  1358  	})
  1359  }
  1360  
  1361  func TestTsconfigWarningsInsideNodeModules(t *testing.T) {
  1362  	tsconfig_suite.expectBundled(t, bundled{
  1363  		files: map[string]string{
  1364  			"/Users/user/project/src/entry.tsx": `
  1365  				import "./foo"
  1366  				import "bar"
  1367  			`,
  1368  
  1369  			"/Users/user/project/src/foo/tsconfig.json": `{ "extends": "extends for foo" }`,
  1370  			"/Users/user/project/src/foo/index.js":      ``,
  1371  
  1372  			"/Users/user/project/src/node_modules/bar/tsconfig.json": `{ "extends": "extends for bar" }`,
  1373  			"/Users/user/project/src/node_modules/bar/index.js":      ``,
  1374  		},
  1375  		entryPaths: []string{"/Users/user/project/src/entry.tsx"},
  1376  		options: config.Options{
  1377  			Mode:          config.ModeBundle,
  1378  			AbsOutputFile: "/Users/user/project/out.js",
  1379  		},
  1380  		expectedScanLog: `Users/user/project/src/foo/tsconfig.json: WARNING: Cannot find base config file "extends for foo"
  1381  `,
  1382  	})
  1383  }
  1384  
  1385  func TestTsconfigRemoveUnusedImports(t *testing.T) {
  1386  	tsconfig_suite.expectBundled(t, bundled{
  1387  		files: map[string]string{
  1388  			"/Users/user/project/src/entry.ts": `
  1389  				import {x, y} from "./foo"
  1390  				console.log(1 as x)
  1391  			`,
  1392  			"/Users/user/project/src/tsconfig.json": `{
  1393  				"compilerOptions": {
  1394  					"importsNotUsedAsValues": "remove"
  1395  				}
  1396  			}`,
  1397  		},
  1398  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1399  		options: config.Options{
  1400  			Mode:          config.ModeBundle,
  1401  			AbsOutputFile: "/Users/user/project/out.js",
  1402  		},
  1403  	})
  1404  }
  1405  
  1406  func TestTsconfigPreserveUnusedImports(t *testing.T) {
  1407  	tsconfig_suite.expectBundled(t, bundled{
  1408  		files: map[string]string{
  1409  			"/Users/user/project/src/entry.ts": `
  1410  				import {x, y} from "./foo"
  1411  				console.log(1 as x)
  1412  			`,
  1413  			"/Users/user/project/src/tsconfig.json": `{
  1414  				"compilerOptions": {
  1415  					"importsNotUsedAsValues": "preserve"
  1416  				}
  1417  			}`,
  1418  		},
  1419  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1420  		options: config.Options{
  1421  			Mode:          config.ModeBundle,
  1422  			AbsOutputFile: "/Users/user/project/out.js",
  1423  			ExternalSettings: config.ExternalSettings{
  1424  				PostResolve: config.ExternalMatchers{Exact: map[string]bool{
  1425  					"/Users/user/project/src/foo": true,
  1426  				}},
  1427  			},
  1428  		},
  1429  	})
  1430  }
  1431  
  1432  func TestTsconfigImportsNotUsedAsValuesPreserve(t *testing.T) {
  1433  	tsconfig_suite.expectBundled(t, bundled{
  1434  		files: map[string]string{
  1435  			"/Users/user/project/src/entry.ts": `
  1436  				import {x, y} from "./foo"
  1437  				import z from "./foo"
  1438  				import * as ns from "./foo"
  1439  				console.log(1 as x, 2 as z, 3 as ns.y)
  1440  			`,
  1441  			"/Users/user/project/src/tsconfig.json": `{
  1442  				"compilerOptions": {
  1443  					"importsNotUsedAsValues": "preserve"
  1444  				}
  1445  			}`,
  1446  		},
  1447  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1448  		options: config.Options{
  1449  			Mode:          config.ModeConvertFormat,
  1450  			OutputFormat:  config.FormatESModule,
  1451  			AbsOutputFile: "/Users/user/project/out.js",
  1452  			ExternalSettings: config.ExternalSettings{
  1453  				PostResolve: config.ExternalMatchers{Exact: map[string]bool{
  1454  					"/Users/user/project/src/foo": true,
  1455  				}},
  1456  			},
  1457  		},
  1458  	})
  1459  }
  1460  
  1461  func TestTsconfigPreserveValueImports(t *testing.T) {
  1462  	tsconfig_suite.expectBundled(t, bundled{
  1463  		files: map[string]string{
  1464  			"/Users/user/project/src/entry.ts": `
  1465  				import {} from "a"
  1466  				import {b1} from "b"
  1467  				import {c1, type c2} from "c"
  1468  				import {d1, d2, type d3} from "d"
  1469  				import {type e1, type e2} from "e"
  1470  				import f1, {} from "f"
  1471  				import g1, {g2} from "g"
  1472  				import h1, {type h2} from "h"
  1473  				import * as i1 from "i"
  1474  				import "j"
  1475  			`,
  1476  			"/Users/user/project/src/tsconfig.json": `{
  1477  				"compilerOptions": {
  1478  					"preserveValueImports": true
  1479  				}
  1480  			}`,
  1481  		},
  1482  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1483  		options: config.Options{
  1484  			Mode:          config.ModeConvertFormat,
  1485  			OutputFormat:  config.FormatESModule,
  1486  			AbsOutputFile: "/Users/user/project/out.js",
  1487  			ExternalSettings: config.ExternalSettings{
  1488  				PostResolve: config.ExternalMatchers{Exact: map[string]bool{
  1489  					"/Users/user/project/src/foo": true,
  1490  				}},
  1491  			},
  1492  		},
  1493  	})
  1494  }
  1495  
  1496  func TestTsconfigPreserveValueImportsAndImportsNotUsedAsValuesPreserve(t *testing.T) {
  1497  	tsconfig_suite.expectBundled(t, bundled{
  1498  		files: map[string]string{
  1499  			"/Users/user/project/src/entry.ts": `
  1500  				import {} from "a"
  1501  				import {b1} from "b"
  1502  				import {c1, type c2} from "c"
  1503  				import {d1, d2, type d3} from "d"
  1504  				import {type e1, type e2} from "e"
  1505  				import f1, {} from "f"
  1506  				import g1, {g2} from "g"
  1507  				import h1, {type h2} from "h"
  1508  				import * as i1 from "i"
  1509  				import "j"
  1510  			`,
  1511  			"/Users/user/project/src/tsconfig.json": `{
  1512  				"compilerOptions": {
  1513  					"importsNotUsedAsValues": "preserve",
  1514  					"preserveValueImports": true
  1515  				}
  1516  			}`,
  1517  		},
  1518  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1519  		options: config.Options{
  1520  			Mode:          config.ModeConvertFormat,
  1521  			OutputFormat:  config.FormatESModule,
  1522  			AbsOutputFile: "/Users/user/project/out.js",
  1523  			ExternalSettings: config.ExternalSettings{
  1524  				PostResolve: config.ExternalMatchers{Exact: map[string]bool{
  1525  					"/Users/user/project/src/foo": true,
  1526  				}},
  1527  			},
  1528  		},
  1529  	})
  1530  }
  1531  
  1532  func TestTsconfigUseDefineForClassFieldsES2020(t *testing.T) {
  1533  	tsconfig_suite.expectBundled(t, bundled{
  1534  		files: map[string]string{
  1535  			"/Users/user/project/src/entry.ts": `
  1536  				Foo = class {
  1537  					useDefine = false
  1538  				}
  1539  			`,
  1540  			"/Users/user/project/src/tsconfig.json": `{
  1541  				"compilerOptions": {
  1542  					"target": "ES2020"
  1543  				}
  1544  			}`,
  1545  		},
  1546  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1547  		options: config.Options{
  1548  			Mode:              config.ModeBundle,
  1549  			AbsOutputFile:     "/Users/user/project/out.js",
  1550  			OriginalTargetEnv: "esnext",
  1551  		},
  1552  	})
  1553  }
  1554  
  1555  func TestTsconfigUseDefineForClassFieldsESNext(t *testing.T) {
  1556  	tsconfig_suite.expectBundled(t, bundled{
  1557  		files: map[string]string{
  1558  			"/Users/user/project/src/entry.ts": `
  1559  				Foo = class {
  1560  					useDefine = true
  1561  				}
  1562  			`,
  1563  			"/Users/user/project/src/tsconfig.json": `{
  1564  				"compilerOptions": {
  1565  					"target": "ESNext"
  1566  				}
  1567  			}`,
  1568  		},
  1569  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1570  		options: config.Options{
  1571  			Mode:              config.ModeBundle,
  1572  			AbsOutputFile:     "/Users/user/project/out.js",
  1573  			OriginalTargetEnv: "esnext",
  1574  		},
  1575  	})
  1576  }
  1577  
  1578  func TestTsconfigUnrecognizedTargetWarning(t *testing.T) {
  1579  	tsconfig_suite.expectBundled(t, bundled{
  1580  		files: map[string]string{
  1581  			"/Users/user/project/src/entry.ts": `
  1582  				import "./a"
  1583  				import "b"
  1584  			`,
  1585  			"/Users/user/project/src/a/index.ts": ``,
  1586  			"/Users/user/project/src/a/tsconfig.json": `{
  1587  				"compilerOptions": {
  1588  					"target": "es4"
  1589  				}
  1590  			}`,
  1591  			"/Users/user/project/src/node_modules/b/index.ts": ``,
  1592  			"/Users/user/project/src/node_modules/b/tsconfig.json": `{
  1593  				"compilerOptions": {
  1594  					"target": "es4"
  1595  				}
  1596  			}`,
  1597  		},
  1598  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1599  		options: config.Options{
  1600  			Mode:          config.ModeBundle,
  1601  			AbsOutputFile: "/Users/user/project/out.js",
  1602  		},
  1603  		expectedScanLog: `Users/user/project/src/a/tsconfig.json: WARNING: Unrecognized target environment "es4"
  1604  `,
  1605  	})
  1606  }
  1607  
  1608  func TestTsconfigIgnoredTargetSilent(t *testing.T) {
  1609  	tsconfig_suite.expectBundled(t, bundled{
  1610  		files: map[string]string{
  1611  			"/Users/user/project/src/entry.ts": `
  1612  				import "./a"
  1613  				import "b"
  1614  			`,
  1615  			"/Users/user/project/src/a/index.ts": ``,
  1616  			"/Users/user/project/src/a/tsconfig.json": `{
  1617  				"compilerOptions": {
  1618  					"target": "es5"
  1619  				}
  1620  			}`,
  1621  			"/Users/user/project/src/node_modules/b/index.ts": ``,
  1622  			"/Users/user/project/src/node_modules/b/tsconfig.json": `{
  1623  				"compilerOptions": {
  1624  					"target": "es5"
  1625  				}
  1626  			}`,
  1627  		},
  1628  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1629  		options: config.Options{
  1630  			Mode:                  config.ModeBundle,
  1631  			AbsOutputFile:         "/Users/user/project/out.js",
  1632  			UnsupportedJSFeatures: es(5),
  1633  			OriginalTargetEnv:     "ES5",
  1634  		},
  1635  	})
  1636  }
  1637  
  1638  func TestTsconfigNoBaseURLExtendsPaths(t *testing.T) {
  1639  	tsconfig_suite.expectBundled(t, bundled{
  1640  		files: map[string]string{
  1641  			"/Users/user/project/src/entry.ts": `
  1642  				import { foo } from "foo"
  1643  				console.log(foo)
  1644  			`,
  1645  			"/Users/user/project/lib/foo.ts": `
  1646  				export let foo = 123
  1647  			`,
  1648  			"/Users/user/project/tsconfig.json": `{
  1649  				"extends": "./base/defaults"
  1650  			}`,
  1651  			"/Users/user/project/base/defaults.json": `{
  1652  				"compilerOptions": {
  1653  					"paths": {
  1654  						"*": ["lib/*"]
  1655  					}
  1656  				}
  1657  			}`,
  1658  		},
  1659  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1660  		options: config.Options{
  1661  			Mode:          config.ModeBundle,
  1662  			AbsOutputFile: "/Users/user/project/out.js",
  1663  		},
  1664  		expectedScanLog: `Users/user/project/base/defaults.json: WARNING: Non-relative path "lib/*" is not allowed when "baseUrl" is not set (did you forget a leading "./"?)
  1665  Users/user/project/src/entry.ts: ERROR: Could not resolve "foo"
  1666  NOTE: You can mark the path "foo" as external to exclude it from the bundle, which will remove this error and leave the unresolved path in the bundle.
  1667  `,
  1668  	})
  1669  }
  1670  
  1671  func TestTsconfigBaseURLExtendsPaths(t *testing.T) {
  1672  	tsconfig_suite.expectBundled(t, bundled{
  1673  		files: map[string]string{
  1674  			"/Users/user/project/src/entry.ts": `
  1675  				import { foo } from "foo"
  1676  				console.log(foo)
  1677  			`,
  1678  			"/Users/user/project/lib/foo.ts": `
  1679  				export let foo = 123
  1680  			`,
  1681  			"/Users/user/project/tsconfig.json": `{
  1682  				"extends": "./base/defaults",
  1683  				"compilerOptions": {
  1684  					"baseUrl": "."
  1685  				}
  1686  			}`,
  1687  			"/Users/user/project/base/defaults.json": `{
  1688  				"compilerOptions": {
  1689  					"paths": {
  1690  						"*": ["lib/*"]
  1691  					}
  1692  				}
  1693  			}`,
  1694  		},
  1695  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1696  		options: config.Options{
  1697  			Mode:          config.ModeBundle,
  1698  			AbsOutputFile: "/Users/user/project/out.js",
  1699  		},
  1700  	})
  1701  }
  1702  
  1703  func TestTsconfigPathsExtendsBaseURL(t *testing.T) {
  1704  	tsconfig_suite.expectBundled(t, bundled{
  1705  		files: map[string]string{
  1706  			"/Users/user/project/src/entry.ts": `
  1707  				import { foo } from "foo"
  1708  				console.log(foo)
  1709  			`,
  1710  			"/Users/user/project/base/test/lib/foo.ts": `
  1711  				export let foo = 123
  1712  			`,
  1713  			"/Users/user/project/tsconfig.json": `{
  1714  				"extends": "./base/defaults",
  1715  				"compilerOptions": {
  1716  					"paths": {
  1717  						"*": ["lib/*"]
  1718  					}
  1719  				}
  1720  			}`,
  1721  			"/Users/user/project/base/defaults.json": `{
  1722  				"compilerOptions": {
  1723  					"baseUrl": "test"
  1724  				}
  1725  			}`,
  1726  		},
  1727  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1728  		options: config.Options{
  1729  			Mode:          config.ModeBundle,
  1730  			AbsOutputFile: "/Users/user/project/out.js",
  1731  		},
  1732  	})
  1733  }
  1734  
  1735  func TestTsconfigPathsInNodeModulesIssue2386(t *testing.T) {
  1736  	tsconfig_suite.expectBundled(t, bundled{
  1737  		files: map[string]string{
  1738  			"/Users/user/project/main.js": `
  1739  				import first from "wow/first";
  1740  				import next from "wow/next";
  1741  				console.log(first, next);
  1742  			`,
  1743  			"/Users/user/project/node_modules/wow/package.json": `{
  1744  				"name": "wow",
  1745  				"type": "module",
  1746  				"private": true,
  1747  				"exports": {
  1748  					"./*": "./dist/*.js"
  1749  				},
  1750  				"typesVersions": {
  1751  					"*": {
  1752  						"*": [
  1753  							"dist/*"
  1754  						]
  1755  					}
  1756  				}
  1757  			}`,
  1758  			"/Users/user/project/node_modules/wow/tsconfig.json": `{
  1759  				"compilerOptions": {
  1760  					"paths": { "wow/*": [ "./*" ] }
  1761  				}
  1762  			}`,
  1763  			"/Users/user/project/node_modules/wow/dist/first.js": `
  1764  				export default "dist";
  1765  			`,
  1766  			"/Users/user/project/node_modules/wow/dist/next.js": `
  1767  				import next from "wow/first";
  1768  				export default next;
  1769  			`,
  1770  			"/Users/user/project/node_modules/wow/first.ts": `
  1771  				export default "source";
  1772  			`,
  1773  		},
  1774  		entryPaths: []string{"/Users/user/project/main.js"},
  1775  		options: config.Options{
  1776  			Mode:          config.ModeBundle,
  1777  			AbsOutputFile: "/Users/user/project/out.js",
  1778  		},
  1779  	})
  1780  }
  1781  
  1782  func TestTsconfigWithStatementAlwaysStrictFalse(t *testing.T) {
  1783  	tsconfig_suite.expectBundled(t, bundled{
  1784  		files: map[string]string{
  1785  			"/Users/user/project/src/entry.ts": `
  1786  				with (x) y
  1787  			`,
  1788  			"/Users/user/project/tsconfig.json": `{
  1789  				"compilerOptions": {
  1790  					"alwaysStrict": false
  1791  				}
  1792  			}`,
  1793  		},
  1794  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1795  		options: config.Options{
  1796  			Mode:          config.ModeBundle,
  1797  			AbsOutputFile: "/Users/user/project/out.js",
  1798  			OutputFormat:  config.FormatIIFE,
  1799  		},
  1800  	})
  1801  }
  1802  
  1803  func TestTsconfigWithStatementAlwaysStrictTrue(t *testing.T) {
  1804  	tsconfig_suite.expectBundled(t, bundled{
  1805  		files: map[string]string{
  1806  			"/Users/user/project/src/entry.ts": `
  1807  				with (x) y
  1808  			`,
  1809  			"/Users/user/project/tsconfig.json": `{
  1810  				"compilerOptions": {
  1811  					"alwaysStrict": true
  1812  				}
  1813  			}`,
  1814  		},
  1815  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1816  		options: config.Options{
  1817  			Mode:          config.ModeBundle,
  1818  			AbsOutputFile: "/Users/user/project/out.js",
  1819  		},
  1820  		expectedScanLog: `Users/user/project/src/entry.ts: ERROR: With statements cannot be used in strict mode
  1821  Users/user/project/tsconfig.json: NOTE: TypeScript's "alwaysStrict" setting was enabled here:
  1822  `,
  1823  	})
  1824  }
  1825  
  1826  func TestTsconfigWithStatementStrictFalse(t *testing.T) {
  1827  	tsconfig_suite.expectBundled(t, bundled{
  1828  		files: map[string]string{
  1829  			"/Users/user/project/src/entry.ts": `
  1830  				with (x) y
  1831  			`,
  1832  			"/Users/user/project/tsconfig.json": `{
  1833  				"compilerOptions": {
  1834  					"strict": false
  1835  				}
  1836  			}`,
  1837  		},
  1838  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1839  		options: config.Options{
  1840  			Mode:          config.ModeBundle,
  1841  			AbsOutputFile: "/Users/user/project/out.js",
  1842  			OutputFormat:  config.FormatIIFE,
  1843  		},
  1844  	})
  1845  }
  1846  
  1847  func TestTsconfigWithStatementStrictTrue(t *testing.T) {
  1848  	tsconfig_suite.expectBundled(t, bundled{
  1849  		files: map[string]string{
  1850  			"/Users/user/project/src/entry.ts": `
  1851  				with (x) y
  1852  			`,
  1853  			"/Users/user/project/tsconfig.json": `{
  1854  				"compilerOptions": {
  1855  					"strict": true
  1856  				}
  1857  			}`,
  1858  		},
  1859  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1860  		options: config.Options{
  1861  			Mode:          config.ModeBundle,
  1862  			AbsOutputFile: "/Users/user/project/out.js",
  1863  		},
  1864  		expectedScanLog: `Users/user/project/src/entry.ts: ERROR: With statements cannot be used in strict mode
  1865  Users/user/project/tsconfig.json: NOTE: TypeScript's "strict" setting was enabled here:
  1866  `,
  1867  	})
  1868  }
  1869  
  1870  func TestTsconfigWithStatementStrictFalseAlwaysStrictTrue(t *testing.T) {
  1871  	tsconfig_suite.expectBundled(t, bundled{
  1872  		files: map[string]string{
  1873  			"/Users/user/project/src/entry.ts": `
  1874  				with (x) y
  1875  			`,
  1876  			"/Users/user/project/tsconfig.json": `{
  1877  				"compilerOptions": {
  1878  					"strict": false,
  1879  					"alwaysStrict": true
  1880  				}
  1881  			}`,
  1882  		},
  1883  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1884  		options: config.Options{
  1885  			Mode:          config.ModeBundle,
  1886  			AbsOutputFile: "/Users/user/project/out.js",
  1887  		},
  1888  		expectedScanLog: `Users/user/project/src/entry.ts: ERROR: With statements cannot be used in strict mode
  1889  Users/user/project/tsconfig.json: NOTE: TypeScript's "alwaysStrict" setting was enabled here:
  1890  `,
  1891  	})
  1892  }
  1893  
  1894  func TestTsconfigWithStatementStrictTrueAlwaysStrictFalse(t *testing.T) {
  1895  	tsconfig_suite.expectBundled(t, bundled{
  1896  		files: map[string]string{
  1897  			"/Users/user/project/src/entry.ts": `
  1898  				with (x) y
  1899  			`,
  1900  			"/Users/user/project/tsconfig.json": `{
  1901  				"compilerOptions": {
  1902  					"strict": true,
  1903  					"alwaysStrict": false
  1904  				}
  1905  			}`,
  1906  		},
  1907  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  1908  		options: config.Options{
  1909  			Mode:          config.ModeBundle,
  1910  			AbsOutputFile: "/Users/user/project/out.js",
  1911  			OutputFormat:  config.FormatIIFE,
  1912  		},
  1913  	})
  1914  }
  1915  
  1916  func TestTsconfigAlwaysStrictTrueEmitDirectivePassThrough(t *testing.T) {
  1917  	tsconfig_suite.expectBundled(t, bundled{
  1918  		files: map[string]string{
  1919  			"/Users/user/project/src/implicit.ts": `
  1920  				console.log('this file should start with "use strict"')
  1921  			`,
  1922  			"/Users/user/project/src/explicit.ts": `
  1923  				'use strict'
  1924  				console.log('this file should start with "use strict"')
  1925  			`,
  1926  			"/Users/user/project/tsconfig.json": `{
  1927  				"compilerOptions": {
  1928  					"alwaysStrict": true
  1929  				}
  1930  			}`,
  1931  		},
  1932  		entryPaths: []string{
  1933  			"/Users/user/project/src/implicit.ts",
  1934  			"/Users/user/project/src/explicit.ts",
  1935  		},
  1936  		options: config.Options{
  1937  			Mode:         config.ModePassThrough,
  1938  			AbsOutputDir: "/Users/user/project/out",
  1939  		},
  1940  	})
  1941  }
  1942  
  1943  func TestTsconfigAlwaysStrictTrueEmitDirectiveFormat(t *testing.T) {
  1944  	tsconfig_suite.expectBundled(t, bundled{
  1945  		files: map[string]string{
  1946  			"/Users/user/project/src/implicit.ts": `
  1947  				console.log('this file should start with "use strict"')
  1948  			`,
  1949  			"/Users/user/project/src/explicit.ts": `
  1950  				'use strict'
  1951  				console.log('this file should start with "use strict"')
  1952  			`,
  1953  			"/Users/user/project/tsconfig.json": `{
  1954  				"compilerOptions": {
  1955  					"alwaysStrict": true
  1956  				}
  1957  			}`,
  1958  		},
  1959  		entryPaths: []string{
  1960  			"/Users/user/project/src/implicit.ts",
  1961  			"/Users/user/project/src/explicit.ts",
  1962  		},
  1963  		options: config.Options{
  1964  			Mode:         config.ModeConvertFormat,
  1965  			AbsOutputDir: "/Users/user/project/out",
  1966  		},
  1967  	})
  1968  }
  1969  
  1970  func TestTsconfigAlwaysStrictTrueEmitDirectiveBundleIIFE(t *testing.T) {
  1971  	tsconfig_suite.expectBundled(t, bundled{
  1972  		files: map[string]string{
  1973  			"/Users/user/project/src/implicit.ts": `
  1974  				console.log('this file should start with "use strict"')
  1975  			`,
  1976  			"/Users/user/project/src/explicit.ts": `
  1977  				'use strict'
  1978  				console.log('this file should start with "use strict"')
  1979  			`,
  1980  			"/Users/user/project/tsconfig.json": `{
  1981  				"compilerOptions": {
  1982  					"alwaysStrict": true
  1983  				}
  1984  			}`,
  1985  		},
  1986  		entryPaths: []string{
  1987  			"/Users/user/project/src/implicit.ts",
  1988  			"/Users/user/project/src/explicit.ts",
  1989  		},
  1990  		options: config.Options{
  1991  			Mode:         config.ModeBundle,
  1992  			AbsOutputDir: "/Users/user/project/out",
  1993  			OutputFormat: config.FormatIIFE,
  1994  		},
  1995  	})
  1996  }
  1997  
  1998  func TestTsconfigAlwaysStrictTrueEmitDirectiveBundleCJS(t *testing.T) {
  1999  	tsconfig_suite.expectBundled(t, bundled{
  2000  		files: map[string]string{
  2001  			"/Users/user/project/src/implicit.ts": `
  2002  				console.log('this file should start with "use strict"')
  2003  			`,
  2004  			"/Users/user/project/src/explicit.ts": `
  2005  				'use strict'
  2006  				console.log('this file should start with "use strict"')
  2007  			`,
  2008  			"/Users/user/project/tsconfig.json": `{
  2009  				"compilerOptions": {
  2010  					"alwaysStrict": true
  2011  				}
  2012  			}`,
  2013  		},
  2014  		entryPaths: []string{
  2015  			"/Users/user/project/src/implicit.ts",
  2016  			"/Users/user/project/src/explicit.ts",
  2017  		},
  2018  		options: config.Options{
  2019  			Mode:         config.ModeBundle,
  2020  			AbsOutputDir: "/Users/user/project/out",
  2021  			OutputFormat: config.FormatCommonJS,
  2022  		},
  2023  	})
  2024  }
  2025  
  2026  func TestTsconfigAlwaysStrictTrueEmitDirectiveBundleESM(t *testing.T) {
  2027  	tsconfig_suite.expectBundled(t, bundled{
  2028  		files: map[string]string{
  2029  			"/Users/user/project/src/implicit.ts": `
  2030  				console.log('this file should not start with "use strict"')
  2031  			`,
  2032  			"/Users/user/project/src/explicit.ts": `
  2033  				'use strict'
  2034  				console.log('this file should not start with "use strict"')
  2035  			`,
  2036  			"/Users/user/project/tsconfig.json": `{
  2037  				"compilerOptions": {
  2038  					"alwaysStrict": true
  2039  				}
  2040  			}`,
  2041  		},
  2042  		entryPaths: []string{
  2043  			"/Users/user/project/src/implicit.ts",
  2044  			"/Users/user/project/src/explicit.ts",
  2045  		},
  2046  		options: config.Options{
  2047  			Mode:         config.ModeBundle,
  2048  			AbsOutputDir: "/Users/user/project/out",
  2049  			OutputFormat: config.FormatESModule,
  2050  		},
  2051  	})
  2052  }
  2053  
  2054  func TestTsconfigExtendsDotWithoutSlash(t *testing.T) {
  2055  	tsconfig_suite.expectBundled(t, bundled{
  2056  		files: map[string]string{
  2057  			"/Users/user/project/src/main.tsx": `
  2058  				console.log(<div/>)
  2059  			`,
  2060  			"/Users/user/project/src/foo.json": `{
  2061  				"extends": "."
  2062  			}`,
  2063  			"/Users/user/project/src/tsconfig.json": `{
  2064  				"compilerOptions": {
  2065  					"jsxFactory": "success"
  2066  				}
  2067  			}`,
  2068  		},
  2069  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2070  		options: config.Options{
  2071  			Mode:         config.ModeBundle,
  2072  			AbsOutputDir: "/Users/user/project/out",
  2073  			OutputFormat: config.FormatESModule,
  2074  			TSConfigPath: "/Users/user/project/src/foo.json",
  2075  		},
  2076  	})
  2077  }
  2078  
  2079  func TestTsconfigExtendsDotDotWithoutSlash(t *testing.T) {
  2080  	tsconfig_suite.expectBundled(t, bundled{
  2081  		files: map[string]string{
  2082  			"/Users/user/project/src/main.tsx": `
  2083  				console.log(<div/>)
  2084  			`,
  2085  			"/Users/user/project/src/tsconfig.json": `{
  2086  				"extends": ".."
  2087  			}`,
  2088  			"/Users/user/project/tsconfig.json": `{
  2089  				"compilerOptions": {
  2090  					"jsxFactory": "success"
  2091  				}
  2092  			}`,
  2093  		},
  2094  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2095  		options: config.Options{
  2096  			Mode:         config.ModeBundle,
  2097  			AbsOutputDir: "/Users/user/project/out",
  2098  			OutputFormat: config.FormatESModule,
  2099  		},
  2100  	})
  2101  }
  2102  
  2103  func TestTsconfigExtendsDotWithSlash(t *testing.T) {
  2104  	tsconfig_suite.expectBundled(t, bundled{
  2105  		files: map[string]string{
  2106  			"/Users/user/project/src/main.tsx": `
  2107  				console.log(<div/>)
  2108  			`,
  2109  			"/Users/user/project/src/foo.json": `{
  2110  				"extends": "./"
  2111  			}`,
  2112  			"/Users/user/project/src/tsconfig.json": `{
  2113  				"compilerOptions": {
  2114  					"jsxFactory": "FAILURE"
  2115  				}
  2116  			}`,
  2117  		},
  2118  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2119  		options: config.Options{
  2120  			Mode:         config.ModeBundle,
  2121  			AbsOutputDir: "/Users/user/project/out",
  2122  			OutputFormat: config.FormatESModule,
  2123  			TSConfigPath: "/Users/user/project/src/foo.json",
  2124  		},
  2125  		expectedScanLog: `Users/user/project/src/foo.json: WARNING: Cannot find base config file "./"
  2126  `,
  2127  	})
  2128  }
  2129  
  2130  func TestTsconfigExtendsDotDotWithSlash(t *testing.T) {
  2131  	tsconfig_suite.expectBundled(t, bundled{
  2132  		files: map[string]string{
  2133  			"/Users/user/project/src/main.tsx": `
  2134  				console.log(<div/>)
  2135  			`,
  2136  			"/Users/user/project/src/tsconfig.json": `{
  2137  				"extends": "../"
  2138  			}`,
  2139  			"/Users/user/project/tsconfig.json": `{
  2140  				"compilerOptions": {
  2141  					"jsxFactory": "FAILURE"
  2142  				}
  2143  			}`,
  2144  		},
  2145  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2146  		options: config.Options{
  2147  			Mode:         config.ModeBundle,
  2148  			AbsOutputDir: "/Users/user/project/out",
  2149  			OutputFormat: config.FormatESModule,
  2150  		},
  2151  		expectedScanLog: `Users/user/project/src/tsconfig.json: WARNING: Cannot find base config file "../"
  2152  `,
  2153  	})
  2154  }
  2155  
  2156  func TestTsconfigExtendsWithExports(t *testing.T) {
  2157  	tsconfig_suite.expectBundled(t, bundled{
  2158  		files: map[string]string{
  2159  			"/Users/user/project/src/main.tsx": `
  2160  				console.log(<div/>)
  2161  			`,
  2162  			"/Users/user/project/tsconfig.json": `{
  2163  				"extends": "@whatever/tsconfig/a/b/c"
  2164  			}`,
  2165  			"/Users/user/project/node_modules/@whatever/tsconfig/package.json": `{
  2166  				"exports": {
  2167  					"./a/b/c": "./foo.json"
  2168  				}
  2169  			}`,
  2170  			"/Users/user/project/node_modules/@whatever/tsconfig/foo.json": `{
  2171  				"compilerOptions": {
  2172  					"jsxFactory": "success"
  2173  				}
  2174  			}`,
  2175  		},
  2176  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2177  		options: config.Options{
  2178  			Mode:         config.ModeBundle,
  2179  			AbsOutputDir: "/Users/user/project/out",
  2180  			OutputFormat: config.FormatESModule,
  2181  		},
  2182  	})
  2183  }
  2184  
  2185  func TestTsconfigExtendsWithExportsStar(t *testing.T) {
  2186  	tsconfig_suite.expectBundled(t, bundled{
  2187  		files: map[string]string{
  2188  			"/Users/user/project/src/main.tsx": `
  2189  				console.log(<div/>)
  2190  			`,
  2191  			"/Users/user/project/tsconfig.json": `{
  2192  				"extends": "@whatever/tsconfig/a/b/c"
  2193  			}`,
  2194  			"/Users/user/project/node_modules/@whatever/tsconfig/package.json": `{
  2195  				"exports": {
  2196  					"./*": "./tsconfig.*.json"
  2197  				}
  2198  			}`,
  2199  			"/Users/user/project/node_modules/@whatever/tsconfig/tsconfig.a/b/c.json": `{
  2200  				"compilerOptions": {
  2201  					"jsxFactory": "success"
  2202  				}
  2203  			}`,
  2204  		},
  2205  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2206  		options: config.Options{
  2207  			Mode:         config.ModeBundle,
  2208  			AbsOutputDir: "/Users/user/project/out",
  2209  			OutputFormat: config.FormatESModule,
  2210  		},
  2211  	})
  2212  }
  2213  
  2214  func TestTsconfigExtendsWithExportsStarTrailing(t *testing.T) {
  2215  	tsconfig_suite.expectBundled(t, bundled{
  2216  		files: map[string]string{
  2217  			"/Users/user/project/src/main.tsx": `
  2218  				console.log(<div/>)
  2219  			`,
  2220  			"/Users/user/project/tsconfig.json": `{
  2221  				"extends": "@whatever/tsconfig/a/b/c.json"
  2222  			}`,
  2223  			"/Users/user/project/node_modules/@whatever/tsconfig/package.json": `{
  2224  				"exports": {
  2225  					"./*": "./tsconfig.*"
  2226  				}
  2227  			}`,
  2228  			"/Users/user/project/node_modules/@whatever/tsconfig/tsconfig.a/b/c.json": `{
  2229  				"compilerOptions": {
  2230  					"jsxFactory": "success"
  2231  				}
  2232  			}`,
  2233  		},
  2234  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2235  		options: config.Options{
  2236  			Mode:         config.ModeBundle,
  2237  			AbsOutputDir: "/Users/user/project/out",
  2238  			OutputFormat: config.FormatESModule,
  2239  		},
  2240  	})
  2241  }
  2242  
  2243  func TestTsconfigExtendsWithExportsRequire(t *testing.T) {
  2244  	tsconfig_suite.expectBundled(t, bundled{
  2245  		files: map[string]string{
  2246  			"/Users/user/project/src/main.tsx": `
  2247  				console.log(<div/>)
  2248  			`,
  2249  			"/Users/user/project/tsconfig.json": `{
  2250  				"extends": "@whatever/tsconfig/a/b/c.json"
  2251  			}`,
  2252  			"/Users/user/project/node_modules/@whatever/tsconfig/package.json": `{
  2253  				"exports": {
  2254  					"./*": {
  2255  						"import": "./import.json",
  2256  						"require": "./require.json",
  2257  						"default": "./default.json"
  2258  					}
  2259  				}
  2260  			}`,
  2261  			"/Users/user/project/node_modules/@whatever/tsconfig/import.json":  `FAILURE`,
  2262  			"/Users/user/project/node_modules/@whatever/tsconfig/default.json": `FAILURE`,
  2263  			"/Users/user/project/node_modules/@whatever/tsconfig/require.json": `{
  2264  				"compilerOptions": {
  2265  					"jsxFactory": "success"
  2266  				}
  2267  			}`,
  2268  		},
  2269  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2270  		options: config.Options{
  2271  			Mode:         config.ModeBundle,
  2272  			AbsOutputDir: "/Users/user/project/out",
  2273  			OutputFormat: config.FormatESModule,
  2274  		},
  2275  	})
  2276  }
  2277  
  2278  func TestTsconfigVerbatimModuleSyntaxTrue(t *testing.T) {
  2279  	tsconfig_suite.expectBundled(t, bundled{
  2280  		files: map[string]string{
  2281  			"/Users/user/project/src/main.ts": `
  2282  				export { Car } from "./car";
  2283  				import type * as car from "./car";
  2284  				import { type Car } from "./car";
  2285  				export { type Car } from "./car";
  2286  				import type { A } from "a";
  2287  				import { b, type c, type d } from "bcd";
  2288  				import { type xyz } from "xyz";
  2289  			`,
  2290  			"/Users/user/project/tsconfig.json": `{
  2291  				"compilerOptions": {
  2292  					"verbatimModuleSyntax": true
  2293  				}
  2294  			}`,
  2295  		},
  2296  		entryPaths: []string{"/Users/user/project/src/main.ts"},
  2297  		options: config.Options{
  2298  			Mode:         config.ModePassThrough,
  2299  			AbsOutputDir: "/Users/user/project/out",
  2300  		},
  2301  	})
  2302  }
  2303  
  2304  func TestTsconfigVerbatimModuleSyntaxFalse(t *testing.T) {
  2305  	tsconfig_suite.expectBundled(t, bundled{
  2306  		files: map[string]string{
  2307  			"/Users/user/project/src/main.ts": `
  2308  				export { Car } from "./car";
  2309  				import type * as car from "./car";
  2310  				import { type Car } from "./car";
  2311  				export { type Car } from "./car";
  2312  				import type { A } from "a";
  2313  				import { b, type c, type d } from "bcd";
  2314  				import { type xyz } from "xyz";
  2315  			`,
  2316  			"/Users/user/project/tsconfig.json": `{
  2317  				"compilerOptions": {
  2318  					"verbatimModuleSyntax": false
  2319  				}
  2320  			}`,
  2321  		},
  2322  		entryPaths: []string{"/Users/user/project/src/main.ts"},
  2323  		options: config.Options{
  2324  			Mode:         config.ModePassThrough,
  2325  			AbsOutputDir: "/Users/user/project/out",
  2326  		},
  2327  	})
  2328  }
  2329  
  2330  func TestTsconfigExtendsArray(t *testing.T) {
  2331  	tsconfig_suite.expectBundled(t, bundled{
  2332  		files: map[string]string{
  2333  			"/Users/user/project/src/main.tsx": `
  2334  				declare let h: any, frag: any
  2335  				console.log(<><div /></>)
  2336  			`,
  2337  			"/Users/user/project/tsconfig.json": `{
  2338  				"extends": [
  2339  					"./a.json",
  2340  					"./b.json",
  2341  				],
  2342  			}`,
  2343  			"/Users/user/project/a.json": `{
  2344  				"compilerOptions": {
  2345  					"jsxFactory": "h",
  2346  					"jsxFragmentFactory": "FAILURE",
  2347  				},
  2348  			}`,
  2349  			"/Users/user/project/b.json": `{
  2350  				"compilerOptions": {
  2351  					"jsxFragmentFactory": "frag",
  2352  				},
  2353  			}`,
  2354  		},
  2355  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2356  		options: config.Options{
  2357  			Mode:         config.ModePassThrough,
  2358  			AbsOutputDir: "/Users/user/project/out",
  2359  		},
  2360  	})
  2361  }
  2362  
  2363  func TestTsconfigExtendsArrayNested(t *testing.T) {
  2364  	tsconfig_suite.expectBundled(t, bundled{
  2365  		files: map[string]string{
  2366  			"/Users/user/project/src/main.tsx": `
  2367  				import { foo } from 'foo'
  2368  				declare let b: any, bBase: any
  2369  				export class Foo {
  2370  					render = () => <><div /></>
  2371  				}
  2372  			`,
  2373  			"/Users/user/project/tsconfig.json": `{
  2374  				"extends": [
  2375  					"./a.json",
  2376  					"./b.json",
  2377  				],
  2378  			}`,
  2379  			"/Users/user/project/a.json": `{
  2380  				"extends": "./a-base.json",
  2381  				"compilerOptions": {
  2382  					"jsxFactory": "a",
  2383  					"jsxFragmentFactory": "a",
  2384  					"target": "ES2015",
  2385  				},
  2386  			}`,
  2387  			"/Users/user/project/a-base.json": `{
  2388  				"compilerOptions": {
  2389  					"jsxFactory": "aBase",
  2390  					"jsxFragmentFactory": "aBase",
  2391  					"target": "ES2022",
  2392  					"verbatimModuleSyntax": true,
  2393  				},
  2394  			}`,
  2395  			"/Users/user/project/b.json": `{
  2396  				"extends": "./b-base.json",
  2397  				"compilerOptions": {
  2398  					"jsxFactory": "b",
  2399  				},
  2400  			}`,
  2401  			"/Users/user/project/b-base.json": `{
  2402  				"compilerOptions": {
  2403  					"jsxFactory": "bBase",
  2404  					"jsxFragmentFactory": "bBase",
  2405  				},
  2406  			}`,
  2407  		},
  2408  		entryPaths: []string{"/Users/user/project/src/main.tsx"},
  2409  		options: config.Options{
  2410  			Mode:              config.ModePassThrough,
  2411  			AbsOutputDir:      "/Users/user/project/out",
  2412  			OriginalTargetEnv: "esnext",
  2413  		},
  2414  	})
  2415  }
  2416  
  2417  func TestTsconfigIgnoreInsideNodeModules(t *testing.T) {
  2418  	tsconfig_suite.expectBundled(t, bundled{
  2419  		files: map[string]string{
  2420  			"/Users/user/project/src/main.ts": `
  2421  				import { foo } from 'js-pkg'
  2422  				import { bar } from 'ts-pkg'
  2423  				import { foo as shimFoo, bar as shimBar } from 'pkg'
  2424  				if (foo !== 'foo') throw 'fail: foo'
  2425  				if (bar !== 'bar') throw 'fail: bar'
  2426  				if (shimFoo !== 'shimFoo') throw 'fail: shimFoo'
  2427  				if (shimBar !== 'shimBar') throw 'fail: shimBar'
  2428  			`,
  2429  			"/Users/user/project/shim.ts": `
  2430  				export let foo = 'shimFoo'
  2431  				export let bar = 'shimBar'
  2432  			`,
  2433  			"/Users/user/project/tsconfig.json": `{
  2434  				"compilerOptions": {
  2435  					"paths": {
  2436  						"pkg": ["./shim"],
  2437  					},
  2438  				},
  2439  			}`,
  2440  			"/Users/user/project/node_modules/js-pkg/index.js": `
  2441  				import { foo as pkgFoo } from 'pkg'
  2442  				export let foo = pkgFoo
  2443  			`,
  2444  			"/Users/user/project/node_modules/ts-pkg/index.ts": `
  2445  				import { bar as pkgBar } from 'pkg'
  2446  				export let bar = pkgBar
  2447  			`,
  2448  			"/Users/user/project/node_modules/pkg/index.js": `
  2449  				export let foo = 'foo'
  2450  				export let bar = 'bar'
  2451  			`,
  2452  		},
  2453  		entryPaths: []string{"/Users/user/project/src/main.ts"},
  2454  		options: config.Options{
  2455  			Mode:         config.ModeBundle,
  2456  			AbsOutputDir: "/Users/user/project/out",
  2457  		},
  2458  	})
  2459  }
  2460  
  2461  func TestTsconfigJsonPackagesExternal(t *testing.T) {
  2462  	tsconfig_suite.expectBundled(t, bundled{
  2463  		files: map[string]string{
  2464  			"/Users/user/project/src/entry.js": `
  2465  				import truePkg from 'pkg1'
  2466  				import falsePkg from 'internal/pkg2'
  2467  				truePkg()
  2468  				falsePkg()
  2469  			`,
  2470  			"/Users/user/project/src/tsconfig.json": `
  2471  				{
  2472  					"compilerOptions": {
  2473  						"paths": {
  2474  							"internal/*": ["./stuff/*"]
  2475  						}
  2476  					}
  2477  				}
  2478  			`,
  2479  			"/Users/user/project/src/stuff/pkg2.js": `
  2480  				export default success
  2481  			`,
  2482  		},
  2483  		entryPaths: []string{"/Users/user/project/src/entry.js"},
  2484  		options: config.Options{
  2485  			Mode:             config.ModeBundle,
  2486  			AbsOutputFile:    "/Users/user/project/out.js",
  2487  			ExternalPackages: true,
  2488  		},
  2489  	})
  2490  }
  2491  
  2492  func TestTsconfigJsonTopLevelMistakeWarning(t *testing.T) {
  2493  	tsconfig_suite.expectBundled(t, bundled{
  2494  		files: map[string]string{
  2495  			"/Users/user/project/src/entry.ts": `
  2496  				@foo
  2497  				class Foo {}
  2498  			`,
  2499  			"/Users/user/project/src/tsconfig.json": `
  2500  				{
  2501  					"experimentalDecorators": true
  2502  				}
  2503  			`,
  2504  		},
  2505  		entryPaths: []string{"/Users/user/project/src/entry.ts"},
  2506  		options: config.Options{
  2507  			Mode:          config.ModeBundle,
  2508  			AbsOutputFile: "/Users/user/project/out.js",
  2509  		},
  2510  		expectedScanLog: `Users/user/project/src/tsconfig.json: WARNING: Expected the "experimentalDecorators" option to be nested inside a "compilerOptions" object
  2511  `,
  2512  	})
  2513  }
  2514  
  2515  // https://github.com/evanw/esbuild/issues/3307
  2516  func TestTsconfigJsonBaseUrlIssue3307(t *testing.T) {
  2517  	tsconfig_suite.expectBundled(t, bundled{
  2518  		files: map[string]string{
  2519  			"/Users/user/project/src/tsconfig.json": `
  2520  				{
  2521  					"compilerOptions": {
  2522  						"baseUrl": "./subdir"
  2523  					}
  2524  				}
  2525  			`,
  2526  			"/Users/user/project/src/test.ts": `
  2527  				export const foo = "well, this is correct...";
  2528  			`,
  2529  			"/Users/user/project/src/subdir/test.ts": `
  2530  				export const foo = "WRONG";
  2531  			`,
  2532  		},
  2533  		entryPaths:    []string{"test.ts"},
  2534  		absWorkingDir: "/Users/user/project/src",
  2535  		options: config.Options{
  2536  			Mode:          config.ModeBundle,
  2537  			AbsOutputFile: "/Users/user/project/out.js",
  2538  		},
  2539  	})
  2540  }
  2541  
  2542  // https://github.com/evanw/esbuild/issues/3354
  2543  func TestTsconfigJsonAsteriskNameCollisionIssue3354(t *testing.T) {
  2544  	tsconfig_suite.expectBundled(t, bundled{
  2545  		files: map[string]string{
  2546  			"/Users/user/project/src/entry.ts": `
  2547  				import {foo} from "foo";
  2548  				foo();
  2549  			`,
  2550  			"/Users/user/project/src/tsconfig.json": `
  2551  				{
  2552  					"compilerOptions": {
  2553  						"baseUrl": ".",
  2554  						"paths": {
  2555  							"*": ["web/*"]
  2556  						}
  2557  					}
  2558  				}
  2559  			`,
  2560  			"/Users/user/project/src/web/foo.ts": `
  2561  				import {foo as barFoo} from 'bar/foo';
  2562  				export function foo() {
  2563  					console.log('web/foo');
  2564  					barFoo();
  2565  				}
  2566  			`,
  2567  			"/Users/user/project/src/web/bar/foo/foo.ts": `
  2568  				export function foo() {
  2569  					console.log('bar/foo');
  2570  				}
  2571  			`,
  2572  			"/Users/user/project/src/web/bar/foo/index.ts": `
  2573  				export {foo} from './foo'
  2574  			`,
  2575  		},
  2576  		entryPaths:    []string{"entry.ts"},
  2577  		absWorkingDir: "/Users/user/project/src",
  2578  		options: config.Options{
  2579  			Mode:          config.ModeBundle,
  2580  			AbsOutputFile: "/Users/user/project/out.js",
  2581  		},
  2582  	})
  2583  }
  2584  
  2585  // https://github.com/evanw/esbuild/issues/3698
  2586  func TestTsconfigPackageJsonExportsYarnPnP(t *testing.T) {
  2587  	tsconfig_suite.expectBundled(t, bundled{
  2588  		files: map[string]string{
  2589  			"/Users/user/project/packages/app/index.tsx": `
  2590  				console.log(<div/>)
  2591  			`,
  2592  			"/Users/user/project/packages/app/tsconfig.json": `
  2593  				{
  2594  					"extends": "tsconfigs/config"
  2595  				}
  2596  			`,
  2597  			"/Users/user/project/packages/tsconfigs/package.json": `
  2598  				{
  2599  					"exports": {
  2600  						"./config": "./configs/tsconfig.json"
  2601  					}
  2602  				}
  2603  			`,
  2604  			"/Users/user/project/packages/tsconfigs/configs/tsconfig.json": `
  2605  				{
  2606  					"compilerOptions": {
  2607  						"jsxFactory": "success"
  2608  					}
  2609  				}
  2610  			`,
  2611  			"/Users/user/project/.pnp.data.json": `
  2612  				{
  2613  					"packageRegistryData": [
  2614  						[
  2615  							"app",
  2616  							[
  2617  								[
  2618  									"workspace:packages/app",
  2619  									{
  2620  										"packageLocation": "./packages/app/",
  2621  										"packageDependencies": [
  2622  											[
  2623  												"tsconfigs",
  2624  												"workspace:packages/tsconfigs"
  2625  											]
  2626  										],
  2627  										"linkType": "SOFT"
  2628  									}
  2629  								]
  2630  							]
  2631  						],
  2632  						[
  2633  							"tsconfigs",
  2634  							[
  2635  								[
  2636  									"workspace:packages/tsconfigs",
  2637  									{
  2638  										"packageLocation": "./packages/tsconfigs/",
  2639  										"packageDependencies": [],
  2640  										"linkType": "SOFT"
  2641  									}
  2642  								]
  2643  							]
  2644  						]
  2645  					]
  2646  				}
  2647  			`,
  2648  		},
  2649  		entryPaths:    []string{"/Users/user/project/packages/app/index.tsx"},
  2650  		absWorkingDir: "/Users/user/project",
  2651  		options: config.Options{
  2652  			Mode:          config.ModeBundle,
  2653  			AbsOutputFile: "/Users/user/project/out.js",
  2654  		},
  2655  	})
  2656  }