4
4
ArrayIsArray,
5
5
ArrayPrototypeJoin,
6
6
ArrayPrototypeShift,
7
+ JSONParse,
7
8
JSONStringify,
8
9
ObjectFreeze,
9
10
ObjectGetOwnPropertyNames,
@@ -23,23 +24,14 @@ const {
23
24
const assert = require ( 'internal/assert' ) ;
24
25
const internalFS = require ( 'internal/fs/utils' ) ;
25
26
const { NativeModule } = require ( 'internal/bootstrap/loaders' ) ;
26
- const {
27
- Module : CJSModule ,
28
- readPackageScope,
29
- readPackage,
30
- packageJsonCache
31
- } = require ( 'internal/modules/cjs/loader' ) ;
32
27
const {
33
28
realpathSync,
34
29
statSync,
35
30
Stats,
36
- openSync,
37
- fstatSync,
38
- readFileSync,
39
- closeSync
40
31
} = require ( 'fs' ) ;
41
32
const { getOptionValue } = require ( 'internal/options' ) ;
42
- const { sep, relative, join } = require ( 'path' ) ;
33
+ const { sep, relative } = require ( 'path' ) ;
34
+ const { Module : CJSModule } = require ( 'internal/modules/cjs/loader' ) ;
43
35
const preserveSymlinks = getOptionValue ( '--preserve-symlinks' ) ;
44
36
const preserveSymlinksMain = getOptionValue ( '--preserve-symlinks-main' ) ;
45
37
const typeFlag = getOptionValue ( '--input-type' ) ;
@@ -55,6 +47,7 @@ const {
55
47
ERR_UNSUPPORTED_ESM_URL_SCHEME ,
56
48
} = require ( 'internal/errors' ) . codes ;
57
49
50
+ const packageJsonReader = require ( 'internal/modules/package_json_reader' ) ;
58
51
const DEFAULT_CONDITIONS = ObjectFreeze ( [ 'node' , 'import' ] ) ;
59
52
const DEFAULT_CONDITIONS_SET = new SafeSet ( DEFAULT_CONDITIONS ) ;
60
53
@@ -70,6 +63,7 @@ function getConditionsSet(conditions) {
70
63
}
71
64
72
65
const realpathCache = new SafeMap ( ) ;
66
+ const packageJSONCache = new SafeMap ( ) ; /* string -> PackageConfig */
73
67
74
68
function tryStatSync ( path ) {
75
69
try {
@@ -79,6 +73,77 @@ function tryStatSync(path) {
79
73
}
80
74
}
81
75
76
+ function getPackageConfig ( path ) {
77
+ const existing = packageJSONCache . get ( path ) ;
78
+ if ( existing !== undefined ) {
79
+ return existing ;
80
+ }
81
+ const source = packageJsonReader . read ( path ) . string ;
82
+ if ( source === undefined ) {
83
+ const packageConfig = {
84
+ exists : false ,
85
+ main : undefined ,
86
+ name : undefined ,
87
+ type : 'none' ,
88
+ exports : undefined
89
+ } ;
90
+ packageJSONCache . set ( path , packageConfig ) ;
91
+ return packageConfig ;
92
+ }
93
+
94
+ let packageJSON ;
95
+ try {
96
+ packageJSON = JSONParse ( source ) ;
97
+ } catch ( error ) {
98
+ const errorPath = StringPrototypeSlice ( path , 0 , path . length - 13 ) ;
99
+ throw new ERR_INVALID_PACKAGE_CONFIG ( errorPath , error . message , true ) ;
100
+ }
101
+
102
+ let { main, name, type } = packageJSON ;
103
+ const { exports } = packageJSON ;
104
+ if ( typeof main !== 'string' ) main = undefined ;
105
+ if ( typeof name !== 'string' ) name = undefined ;
106
+ // Ignore unknown types for forwards compatibility
107
+ if ( type !== 'module' && type !== 'commonjs' ) type = 'none' ;
108
+
109
+ const packageConfig = {
110
+ exists : true ,
111
+ main,
112
+ name,
113
+ type,
114
+ exports
115
+ } ;
116
+ packageJSONCache . set ( path , packageConfig ) ;
117
+ return packageConfig ;
118
+ }
119
+
120
+ function getPackageScopeConfig ( resolved , base ) {
121
+ let packageJSONUrl = new URL ( './package.json' , resolved ) ;
122
+ while ( true ) {
123
+ const packageJSONPath = packageJSONUrl . pathname ;
124
+ if ( StringPrototypeEndsWith ( packageJSONPath , 'node_modules/package.json' ) )
125
+ break ;
126
+ const packageConfig = getPackageConfig ( fileURLToPath ( packageJSONUrl ) , base ) ;
127
+ if ( packageConfig . exists ) return packageConfig ;
128
+
129
+ const lastPackageJSONUrl = packageJSONUrl ;
130
+ packageJSONUrl = new URL ( '../package.json' , packageJSONUrl ) ;
131
+
132
+ // Terminates at root where ../package.json equals ../../package.json
133
+ // (can't just check "/package.json" for Windows support).
134
+ if ( packageJSONUrl . pathname === lastPackageJSONUrl . pathname ) break ;
135
+ }
136
+ const packageConfig = {
137
+ exists : false ,
138
+ main : undefined ,
139
+ name : undefined ,
140
+ type : 'none' ,
141
+ exports : undefined
142
+ } ;
143
+ packageJSONCache . set ( fileURLToPath ( packageJSONUrl ) , packageConfig ) ;
144
+ return packageConfig ;
145
+ }
146
+
82
147
/*
83
148
* Legacy CommonJS main resolution:
84
149
* 1. let M = pkg_url + (json main field)
@@ -331,7 +396,7 @@ function isConditionalExportsMainSugar(exports, packageJSONUrl, base) {
331
396
332
397
333
398
function packageMainResolve ( packageJSONUrl , packageConfig , base , conditions ) {
334
- if ( packageConfig ) {
399
+ if ( packageConfig . exists ) {
335
400
const exports = packageConfig . exports ;
336
401
if ( exports !== undefined ) {
337
402
if ( isConditionalExportsMainSugar ( exports , packageJSONUrl , base ) ) {
@@ -408,51 +473,9 @@ function packageExportsResolve(
408
473
throwExportsNotFound ( packageSubpath , packageJSONUrl , base ) ;
409
474
}
410
475
411
- function readIfFile ( path ) {
412
- let fd ;
413
- try {
414
- fd = openSync ( path , 'r' ) ;
415
- } catch {
416
- return undefined ;
417
- }
418
- try {
419
- if ( ! fstatSync ( fd ) . isFile ( ) ) return undefined ;
420
- return readFileSync ( fd , 'utf8' ) ;
421
- } finally {
422
- closeSync ( fd ) ;
423
- }
424
- }
425
-
426
- function catchInvalidPackage ( error , path ) {
427
- if ( error instanceof SyntaxError ) {
428
- const packageJsonPath = join ( path , 'package.json' ) ;
429
- const message = StringPrototypeSlice (
430
- error . message , ( 'Error parsing ' + packageJsonPath + ': ' ) . length ) ;
431
- throw new ERR_INVALID_PACKAGE_CONFIG ( path , message , true ) ;
432
- }
433
- throw error ;
434
- }
435
-
436
- function readPackageESM ( path ) {
437
- try {
438
- return readPackage ( path , readIfFile ) ;
439
- } catch ( error ) {
440
- catchInvalidPackage ( error , path ) ;
441
- }
442
- }
443
-
444
- function readPackageScopeESM ( url ) {
445
- const path = fileURLToPath ( url ) ;
446
- try {
447
- return readPackageScope ( path , readIfFile ) ;
448
- } catch ( error ) {
449
- catchInvalidPackage ( error , path ) ;
450
- }
451
- }
452
-
453
476
function getPackageType ( url ) {
454
- const packageConfig = readPackageScopeESM ( url ) ;
455
- return packageConfig ? packageConfig . data . type : 'none' ;
477
+ const packageConfig = getPackageScopeConfig ( url , url ) ;
478
+ return packageConfig . type ;
456
479
}
457
480
458
481
/**
@@ -496,13 +519,12 @@ function packageResolve(specifier, base, conditions) {
496
519
'' : '.' + StringPrototypeSlice ( specifier , separatorIndex ) ;
497
520
498
521
// ResolveSelf
499
- const packageScope = readPackageScopeESM ( base ) ;
500
- if ( packageScope !== false ) {
501
- const packageConfig = packageScope . data ;
522
+ const packageConfig = getPackageScopeConfig ( base , base ) ;
523
+ if ( packageConfig . exists ) {
502
524
// TODO(jkrems): Find a way to forward the pair/iterator already generated
503
525
// while executing GetPackageScopeConfig
504
526
let packageJSONUrl ;
505
- for ( const [ filename , packageConfigCandidate ] of packageJsonCache ) {
527
+ for ( const [ filename , packageConfigCandidate ] of packageJSONCache ) {
506
528
if ( packageConfig === packageConfigCandidate ) {
507
529
packageJSONUrl = pathToFileURL ( filename ) ;
508
530
break ;
@@ -540,15 +562,13 @@ function packageResolve(specifier, base, conditions) {
540
562
}
541
563
542
564
// Package match.
543
- const packagePath = StringPrototypeSlice (
544
- packageJSONPath , 0 , packageJSONPath . length - 13 ) ;
545
- const packageConfig = readPackageESM ( packagePath ) ;
565
+ const packageConfig = getPackageConfig ( packageJSONPath , base ) ;
546
566
if ( packageSubpath === './' ) {
547
567
return new URL ( './' , packageJSONUrl ) ;
548
568
} else if ( packageSubpath === '' ) {
549
569
return packageMainResolve ( packageJSONUrl , packageConfig , base ,
550
570
conditions ) ;
551
- } else if ( packageConfig && packageConfig . exports !== undefined ) {
571
+ } else if ( packageConfig . exports !== undefined ) {
552
572
return packageExportsResolve (
553
573
packageJSONUrl , packageSubpath , packageConfig , base , conditions ) ;
554
574
} else {
0 commit comments